class OpenSSL::X509::Certificate
Implementierung eines X.509-Zertifikats gemäß RFC 5280. Bietet Zugriff auf die Attribute eines Zertifikats und ermöglicht das Lesen von Zertifikaten aus einem String, unterstützt aber auch die Erstellung neuer Zertifikate von Grund auf.
Ein Zertifikat aus einer Datei lesen
Certificate kann DER-kodierte Zertifikate und Zertifikate im PEM-Format von OpenSSL verarbeiten.
raw = File.binread "cert.cer" # DER- or PEM-encoded certificate = OpenSSL::X509::Certificate.new raw
Ein Zertifikat in eine Datei speichern
Ein Zertifikat kann im DER-Format kodiert werden
cert = ... File.open("cert.cer", "wb") { |f| f.print cert.to_der }
oder im PEM-Format
cert = ... File.open("cert.pem", "wb") { |f| f.print cert.to_pem }
X.509-Zertifikate sind mit einem privaten/öffentlichen Schlüsselpaar verbunden, typischerweise einem RSA-, DSA- oder ECC-Schlüssel (siehe auch OpenSSL::PKey::RSA, OpenSSL::PKey::DSA und OpenSSL::PKey::EC). Der öffentliche Schlüssel selbst ist im Zertifikat gespeichert und kann in Form eines OpenSSL::PKey abgerufen werden. Zertifikate werden typischerweise verwendet, um einem Schlüsselpaar eine Art Identität zuzuordnen, zum Beispiel verwenden Webserver, die Seiten über HTTPs ausliefern, Zertifikate, um sich dem Benutzer zu authentifizieren.
Das Public Key Infrastructure (PKI)-Modell basiert auf vertrauenswürdigen Zertifizierungsstellen („Root CAs“), die diese Zertifikate ausstellen, so dass Endbenutzer ihr Vertrauen nur auf eine ausgewählte Anzahl von Stellen stützen müssen, die wiederum untergeordnete Stellen beglaubigen, die ihre Zertifikate an Endbenutzer ausstellen.
Das Modul OpenSSL::X509 bietet die Werkzeuge zur Einrichtung einer unabhängigen PKI, ähnlich wie Szenarien, in denen das Kommandozeilentool 'openssl' zum Ausstellen von Zertifikaten in einer privaten PKI verwendet wird.
Erstellung eines Root-CA-Zertifikats und eines Endbenutzer-Zertifikats
Zuerst müssen wir ein „selbstsigniertes“ Root-Zertifikat erstellen. Dazu müssen wir zuerst einen Schlüssel generieren. Bitte beachten Sie, dass die Wahl von „1“ als Seriennummer für echte Zertifikate als Sicherheitslücke gilt. Sichere Wahlmöglichkeiten sind Ganzzahlen im zweistelligen Bytebereich und idealerweise keine sequentiellen, sondern sichere Zufallszahlen. Schritte hier zur Kürze des Beispiels ausgelassen.
root_key = OpenSSL::PKey::RSA.new 2048 # the CA's public/private key root_ca = OpenSSL::X509::Certificate.new root_ca.version = 2 # cf. RFC 5280 - to make it a "v3" certificate root_ca.serial = 1 root_ca.subject = OpenSSL::X509::Name.parse "/DC=org/DC=ruby-lang/CN=Ruby CA" root_ca.issuer = root_ca.subject # root CA's are "self-signed" root_ca.public_key = root_key.public_key root_ca.not_before = Time.now root_ca.not_after = root_ca.not_before + 2 * 365 * 24 * 60 * 60 # 2 years validity ef = OpenSSL::X509::ExtensionFactory.new ef.subject_certificate = root_ca ef.issuer_certificate = root_ca root_ca.add_extension(ef.create_extension("basicConstraints","CA:TRUE",true)) root_ca.add_extension(ef.create_extension("keyUsage","keyCertSign, cRLSign", true)) root_ca.add_extension(ef.create_extension("subjectKeyIdentifier","hash",false)) root_ca.add_extension(ef.create_extension("authorityKeyIdentifier","keyid:always",false)) root_ca.sign(root_key, OpenSSL::Digest.new('SHA256'))
Der nächste Schritt ist die Erstellung des Endbenutzer-Zertifikats unter Verwendung des Root-CA-Zertifikats.
key = OpenSSL::PKey::RSA.new 2048 cert = OpenSSL::X509::Certificate.new cert.version = 2 cert.serial = 2 cert.subject = OpenSSL::X509::Name.parse "/DC=org/DC=ruby-lang/CN=Ruby certificate" cert.issuer = root_ca.subject # root CA is the issuer cert.public_key = key.public_key cert.not_before = Time.now cert.not_after = cert.not_before + 1 * 365 * 24 * 60 * 60 # 1 years validity ef = OpenSSL::X509::ExtensionFactory.new ef.subject_certificate = cert ef.issuer_certificate = root_ca cert.add_extension(ef.create_extension("keyUsage","digitalSignature", true)) cert.add_extension(ef.create_extension("subjectKeyIdentifier","hash",false)) cert.sign(root_key, OpenSSL::Digest.new('SHA256'))
Öffentliche Klassenmethoden
Source
static VALUE
ossl_x509_load(VALUE klass, VALUE buffer)
{
BIO *in = ossl_obj2bio(&buffer);
return rb_ensure(load_chained_certificates, (VALUE)in, load_chained_certificates_ensure, (VALUE)in);
}
Liest die verketteten Zertifikate aus dem gegebenen Eingabestrom. Unterstützt sowohl PEM- als auch DER-kodierte Zertifikate.
PEM ist ein Textformat und unterstützt mehr als ein Zertifikat.
DER ist ein Binärformat und unterstützt nur ein Zertifikat.
Wenn die Datei leer ist oder nur irrelevante Daten enthält, wird eine Ausnahme vom Typ OpenSSL::X509::CertificateError ausgelöst.
Source
# File ext/openssl/lib/openssl/x509.rb, line 369 def self.load_file(path) load(File.binread(path)) end
Source
static VALUE
ossl_x509_initialize(int argc, VALUE *argv, VALUE self)
{
BIO *in;
X509 *x509, *x509_orig = RTYPEDDATA_DATA(self);
VALUE arg;
rb_check_frozen(self);
if (rb_scan_args(argc, argv, "01", &arg) == 0) {
/* create just empty X509Cert */
return self;
}
arg = ossl_to_der_if_possible(arg);
in = ossl_obj2bio(&arg);
x509 = d2i_X509_bio(in, NULL);
if (!x509) {
OSSL_BIO_reset(in);
x509 = PEM_read_bio_X509(in, NULL, NULL, NULL);
}
BIO_free(in);
if (!x509)
ossl_raise(eX509CertError, "PEM_read_bio_X509");
RTYPEDDATA_DATA(self) = x509;
X509_free(x509_orig);
return self;
}
Öffentliche Instanzmethoden
Source
static VALUE
ossl_x509_eq(VALUE self, VALUE other)
{
X509 *a, *b;
GetX509(self, a);
if (!rb_obj_is_kind_of(other, cX509Cert))
return Qfalse;
GetX509(other, b);
return !X509_cmp(a, b) ? Qtrue : Qfalse;
}
Vergleicht die beiden Zertifikate. Beachten Sie, dass dies alle Felder berücksichtigt, nicht nur den Ausstellernamen und die Seriennummer.
Diese Methode verwendet X509_cmp() von OpenSSL, die Zertifikate basierend auf ihren zwischengespeicherten DER-Kodierungen vergleicht. Der Vergleich kann unzuverlässig sein, wenn ein Zertifikat unvollständig ist.
Siehe auch die Manpage X509_cmp(3).
Source
static VALUE
ossl_x509_add_extension(VALUE self, VALUE extension)
{
X509 *x509;
X509_EXTENSION *ext;
GetX509(self, x509);
ext = GetX509ExtPtr(extension);
if (!X509_add_ext(x509, ext, -1)) { /* DUPs ext - FREE it */
ossl_raise(eX509CertError, NULL);
}
return extension;
}
Source
static VALUE
ossl_x509_check_private_key(VALUE self, VALUE key)
{
X509 *x509;
EVP_PKEY *pkey;
/* not needed private key, but should be */
pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */
GetX509(self, x509);
if (!X509_check_private_key(x509, pkey)) {
ossl_clear_error();
return Qfalse;
}
return Qtrue;
}
Gibt true zurück, wenn key der entsprechende private Schlüssel für die Subject Public Key Information ist, andernfalls false.
Source
static VALUE
ossl_x509_get_extensions(VALUE self)
{
X509 *x509;
int count, i;
X509_EXTENSION *ext;
VALUE ary;
GetX509(self, x509);
count = X509_get_ext_count(x509);
ary = rb_ary_new_capa(count);
for (i=0; i<count; i++) {
ext = X509_get_ext(x509, i); /* NO DUP - don't free! */
rb_ary_push(ary, ossl_x509ext_new(ext));
}
return ary;
}
Source
static VALUE
ossl_x509_set_extensions(VALUE self, VALUE ary)
{
X509 *x509;
X509_EXTENSION *ext;
long i;
Check_Type(ary, T_ARRAY);
/* All ary's members should be X509Extension */
for (i=0; i<RARRAY_LEN(ary); i++) {
OSSL_Check_Kind(RARRAY_AREF(ary, i), cX509Ext);
}
GetX509(self, x509);
for (i = X509_get_ext_count(x509); i > 0; i--)
X509_EXTENSION_free(X509_delete_ext(x509, 0));
for (i=0; i<RARRAY_LEN(ary); i++) {
ext = GetX509ExtPtr(RARRAY_AREF(ary, i));
if (!X509_add_ext(x509, ext, -1)) { /* DUPs ext */
ossl_raise(eX509CertError, "X509_add_ext");
}
}
return ary;
}
Source
# File ext/openssl/lib/openssl/x509.rb, line 349 def inspect "#<#{self.class}: " \ "subject=#{subject.inspect}, " \ "issuer=#{issuer.inspect}, " \ "serial=#{serial.inspect}, " \ "not_before=#{not_before.inspect rescue "(error)"}, " \ "not_after=#{not_after.inspect rescue "(error)"}>" end
Source
static VALUE
ossl_x509_get_issuer(VALUE self)
{
X509 *x509;
X509_NAME *name;
GetX509(self, x509);
if(!(name = X509_get_issuer_name(x509))) { /* NO DUP - don't free! */
ossl_raise(eX509CertError, NULL);
}
return ossl_x509name_new(name);
}
Source
static VALUE
ossl_x509_set_issuer(VALUE self, VALUE issuer)
{
X509 *x509;
GetX509(self, x509);
if (!X509_set_issuer_name(x509, GetX509NamePtr(issuer))) { /* DUPs name */
ossl_raise(eX509CertError, NULL);
}
return issuer;
}
Source
static VALUE
ossl_x509_get_not_after(VALUE self)
{
X509 *x509;
const ASN1_TIME *asn1time;
GetX509(self, x509);
if (!(asn1time = X509_get0_notAfter(x509))) {
ossl_raise(eX509CertError, NULL);
}
return asn1time_to_time(asn1time);
}
Source
static VALUE
ossl_x509_set_not_after(VALUE self, VALUE time)
{
X509 *x509;
ASN1_TIME *asn1time;
GetX509(self, x509);
asn1time = ossl_x509_time_adjust(NULL, time);
if (!X509_set1_notAfter(x509, asn1time)) {
ASN1_TIME_free(asn1time);
ossl_raise(eX509CertError, "X509_set_notAfter");
}
ASN1_TIME_free(asn1time);
return time;
}
Source
static VALUE
ossl_x509_get_not_before(VALUE self)
{
X509 *x509;
const ASN1_TIME *asn1time;
GetX509(self, x509);
if (!(asn1time = X509_get0_notBefore(x509))) {
ossl_raise(eX509CertError, NULL);
}
return asn1time_to_time(asn1time);
}
Source
static VALUE
ossl_x509_set_not_before(VALUE self, VALUE time)
{
X509 *x509;
ASN1_TIME *asn1time;
GetX509(self, x509);
asn1time = ossl_x509_time_adjust(NULL, time);
if (!X509_set1_notBefore(x509, asn1time)) {
ASN1_TIME_free(asn1time);
ossl_raise(eX509CertError, "X509_set_notBefore");
}
ASN1_TIME_free(asn1time);
return time;
}
Source
# File ext/openssl/lib/openssl/x509.rb, line 358 def pretty_print(q) q.object_group(self) { q.breakable q.text 'subject='; q.pp self.subject; q.text ','; q.breakable q.text 'issuer='; q.pp self.issuer; q.text ','; q.breakable q.text 'serial='; q.pp self.serial; q.text ','; q.breakable q.text 'not_before='; q.pp self.not_before; q.text ','; q.breakable q.text 'not_after='; q.pp self.not_after } end
Source
static VALUE
ossl_x509_get_public_key(VALUE self)
{
X509 *x509;
EVP_PKEY *pkey;
GetX509(self, x509);
if (!(pkey = X509_get_pubkey(x509))) { /* adds an reference */
ossl_raise(eX509CertError, NULL);
}
return ossl_pkey_wrap(pkey);
}
Source
static VALUE
ossl_x509_set_public_key(VALUE self, VALUE key)
{
X509 *x509;
EVP_PKEY *pkey;
GetX509(self, x509);
pkey = GetPKeyPtr(key);
ossl_pkey_check_public_key(pkey);
if (!X509_set_pubkey(x509, pkey))
ossl_raise(eX509CertError, "X509_set_pubkey");
return key;
}
Source
static VALUE
ossl_x509_get_serial(VALUE self)
{
X509 *x509;
GetX509(self, x509);
return asn1integer_to_num(X509_get_serialNumber(x509));
}
Source
static VALUE
ossl_x509_set_serial(VALUE self, VALUE num)
{
X509 *x509;
GetX509(self, x509);
X509_set_serialNumber(x509, num_to_asn1integer(num, X509_get_serialNumber(x509)));
return num;
}
Source
static VALUE
ossl_x509_sign(VALUE self, VALUE key, VALUE digest)
{
X509 *x509;
EVP_PKEY *pkey;
const EVP_MD *md;
VALUE md_holder;
pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */
/* NULL needed for some key types, e.g. Ed25519 */
md = NIL_P(digest) ? NULL : ossl_evp_md_fetch(digest, &md_holder);
GetX509(self, x509);
if (!X509_sign(x509, pkey, md))
ossl_raise(eX509CertError, "X509_sign");
return self;
}
Source
static VALUE
ossl_x509_get_signature_algorithm(VALUE self)
{
X509 *x509;
const ASN1_OBJECT *obj;
GetX509(self, x509);
X509_ALGOR_get0(&obj, NULL, NULL, X509_get0_tbs_sigalg(x509));
return ossl_asn1obj_to_string_long_name(obj);
}
Gibt den für die Signatur dieses Zertifikats verwendeten Signaturalgorithmus zurück. Dies gibt den Algorithmusnamen zurück, der in der TBSCertificate-Struktur gefunden wird, nicht in der äußeren Certificate-Struktur.
Gibt den Langnamen des Signaturalgorithmus zurück oder die Punkt-Dezimalnotation, falls OpenSSL keinen Langnamen dafür definiert hat.
Source
static VALUE
ossl_x509_get_subject(VALUE self)
{
X509 *x509;
X509_NAME *name;
GetX509(self, x509);
if (!(name = X509_get_subject_name(x509))) { /* NO DUP - don't free! */
ossl_raise(eX509CertError, NULL);
}
return ossl_x509name_new(name);
}
Source
static VALUE
ossl_x509_set_subject(VALUE self, VALUE subject)
{
X509 *x509;
GetX509(self, x509);
if (!X509_set_subject_name(x509, GetX509NamePtr(subject))) { /* DUPs name */
ossl_raise(eX509CertError, NULL);
}
return subject;
}
Source
static VALUE
ossl_x509_tbs_bytes(VALUE self)
{
X509 *x509;
int len;
unsigned char *p0;
VALUE str;
GetX509(self, x509);
len = i2d_re_X509_tbs(x509, NULL);
if (len <= 0) {
ossl_raise(eX509CertError, "i2d_re_X509_tbs");
}
str = rb_str_new(NULL, len);
p0 = (unsigned char *)RSTRING_PTR(str);
if (i2d_re_X509_tbs(x509, &p0) <= 0) {
ossl_raise(eX509CertError, "i2d_re_X509_tbs");
}
ossl_str_adjust(str, p0);
return str;
}
Gibt die DER-kodierten Bytes des zu signierenden Zertifikats zurück. Dies ist hauptsächlich nützlich für die Validierung von eingebetteten Certificate Transparency-Signaturen.
Source
static VALUE
ossl_x509_to_der(VALUE self)
{
X509 *x509;
VALUE str;
long len;
unsigned char *p;
GetX509(self, x509);
if ((len = i2d_X509(x509, NULL)) <= 0)
ossl_raise(eX509CertError, NULL);
str = rb_str_new(0, len);
p = (unsigned char *)RSTRING_PTR(str);
if (i2d_X509(x509, &p) <= 0)
ossl_raise(eX509CertError, NULL);
ossl_str_adjust(str, p);
return str;
}
Source
static VALUE
ossl_x509_to_pem(VALUE self)
{
X509 *x509;
BIO *out;
VALUE str;
GetX509(self, x509);
out = BIO_new(BIO_s_mem());
if (!out) ossl_raise(eX509CertError, NULL);
if (!PEM_write_bio_X509(out, x509)) {
BIO_free(out);
ossl_raise(eX509CertError, NULL);
}
str = ossl_membio2str(out);
return str;
}
Source
static VALUE
ossl_x509_to_text(VALUE self)
{
X509 *x509;
BIO *out;
VALUE str;
GetX509(self, x509);
out = BIO_new(BIO_s_mem());
if (!out) ossl_raise(eX509CertError, NULL);
if (!X509_print(out, x509)) {
BIO_free(out);
ossl_raise(eX509CertError, NULL);
}
str = ossl_membio2str(out);
return str;
}
Source
static VALUE
ossl_x509_verify(VALUE self, VALUE key)
{
X509 *x509;
EVP_PKEY *pkey;
GetX509(self, x509);
pkey = GetPKeyPtr(key);
ossl_pkey_check_public_key(pkey);
switch (X509_verify(x509, pkey)) {
case 1:
return Qtrue;
case 0:
ossl_clear_error();
return Qfalse;
default:
ossl_raise(eX509CertError, NULL);
}
}
Überprüft die Signatur des Zertifikats mit dem öffentlichen Schlüssel key. key muss eine Instanz von OpenSSL::PKey sein.
Source
static VALUE
ossl_x509_get_version(VALUE self)
{
X509 *x509;
GetX509(self, x509);
return LONG2NUM(X509_get_version(x509));
}
Source
static VALUE
ossl_x509_set_version(VALUE self, VALUE version)
{
X509 *x509;
long ver;
if ((ver = NUM2LONG(version)) < 0) {
ossl_raise(eX509CertError, "version must be >= 0!");
}
GetX509(self, x509);
if (!X509_set_version(x509, ver)) {
ossl_raise(eX509CertError, NULL);
}
return version;
}