Class: OpenSSL::X509::Certificate
- Inherits:
-
Object
- Object
- OpenSSL::X509::Certificate
- Defined in:
- ossl_x509cert.c,
lib/openssl/x509.rb,
ossl_x509cert.c
Overview
Implementation of an X.509 certificate as specified in RFC 5280. Provides access to a certificate’s attributes and allows certificates to be read from a string, but also supports the creation of new certificates from scratch.
Reading a certificate from a file
Certificate is capable of handling DER-encoded certificates and certificates encoded in OpenSSL’s PEM format.
raw = File.read "cert.cer" # DER- or PEM-encoded
certificate = OpenSSL::X509::Certificate.new raw
Saving a certificate to a file
A certificate may be encoded in DER format
cert = ...
File.open("cert.cer", "wb") { |f| f.print cert.to_der }
or in PEM format
cert = ...
File.open("cert.pem", "wb") { |f| f.print cert.to_pem }
X.509 certificates are associated with a private/public key pair, typically a RSA, DSA or ECC key (see also OpenSSL::PKey::RSA, OpenSSL::PKey::DSA and OpenSSL::PKey::EC), the public key itself is stored within the certificate and can be accessed in form of an OpenSSL::PKey. Certificates are typically used to be able to associate some form of identity with a key pair, for example web servers serving pages over HTTPs use certificates to authenticate themselves to the user.
The public key infrastructure (PKI) model relies on trusted certificate authorities (“root CAs”) that issue these certificates, so that end users need to base their trust just on a selected few authorities that themselves again vouch for subordinate CAs issuing their certificates to end users.
The OpenSSL::X509 module provides the tools to set up an independent PKI, similar to scenarios where the ‘openssl’ command line tool is used for issuing certificates in a private PKI.
Creating a root CA certificate and an end-entity certificate
First, we need to create a “self-signed” root certificate. To do so, we need to generate a key first. Please note that the choice of “1” as a serial number is considered a security flaw for real certificates. Secure choices are integers in the two-digit byte range and ideally not sequential but secure random numbers, steps omitted here to keep the example concise.
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::SHA256.new)
The next step is to create the end-entity certificate using the root CA certificate.
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::SHA256.new)
Instance Method Summary collapse
- #add_extension(extension) ⇒ Object
-
#check_private_key(key) ⇒ Object
Checks if ‘key’ is PRIV key for this cert.
- #extensions ⇒ Array
- #extensions=(ary) ⇒ Object
- #initialize(*args) ⇒ Object constructor
- #inspect ⇒ Object
- #issuer ⇒ Object
- #issuer=(name) ⇒ Object
- #not_after ⇒ Time
- #not_after=(time) ⇒ Time
- #not_before ⇒ Time
- #not_before=(time) ⇒ Time
- #pretty_print(q) ⇒ Object
- #public_key ⇒ Object
- #public_key=(key) ⇒ Object
- #serial ⇒ Integer
- #serial=(integer) ⇒ Integer
- #sign(key, digest) ⇒ self
- #signature_algorithm ⇒ String
- #subject ⇒ Object
- #subject=(name) ⇒ Object
- #to_der ⇒ String
- #to_pem ⇒ String (also: #to_s)
- #to_text ⇒ String
-
#verify(key) ⇒ Object
Checks that cert signature is made with PRIVversion of this PUBLIC ‘key’.
- #version ⇒ Integer
- #version=(integer) ⇒ Integer
Constructor Details
#new ⇒ Object #new(string) ⇒ Object
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 |
# File 'ossl_x509cert.c', line 149
static VALUE
ossl_x509_initialize(int argc, VALUE *argv, VALUE self)
{
BIO *in;
X509 *x509, *x = DATA_PTR(self);
VALUE arg;
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 = PEM_read_bio_X509(in, &x, NULL, NULL);
DATA_PTR(self) = x;
if (!x509) {
OSSL_BIO_reset(in);
x509 = d2i_X509_bio(in, &x);
DATA_PTR(self) = x;
}
BIO_free(in);
if (!x509) ossl_raise(eX509CertError, NULL);
return self;
}
|
Instance Method Details
#add_extension(extension) ⇒ Object
690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 |
# File 'ossl_x509cert.c', line 690
static VALUE
ossl_x509_add_extension(VALUE self, VALUE extension)
{
X509 *x509;
X509_EXTENSION *ext;
GetX509(self, x509);
ext = DupX509ExtPtr(extension);
if (!X509_add_ext(x509, ext, -1)) { /* DUPs ext - FREE it */
X509_EXTENSION_free(ext);
ossl_raise(eX509CertError, NULL);
}
X509_EXTENSION_free(ext);
return extension;
}
|
#check_private_key(key) ⇒ Object
Checks if ‘key’ is PRIV key for this cert
611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 |
# File 'ossl_x509cert.c', line 611
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_Warning("Check private key:%s", OSSL_ErrMsg());
return Qfalse;
}
return Qtrue;
}
|
#extensions ⇒ Array
632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 |
# File 'ossl_x509cert.c', line 632
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);
if (count < 0) {
return rb_ary_new();
}
ary = rb_ary_new2(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;
}
|
#extensions=(ary) ⇒ Object
658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 |
# File 'ossl_x509cert.c', line 658
static VALUE
ossl_x509_set_extensions(VALUE self, VALUE ary)
{
X509 *x509;
X509_EXTENSION *ext;
int 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_PTR(ary)[i], cX509Ext);
}
GetX509(self, x509);
sk_X509_EXTENSION_pop_free(x509->cert_info->extensions, X509_EXTENSION_free);
x509->cert_info->extensions = NULL;
for (i=0; i<RARRAY_LEN(ary); i++) {
ext = DupX509ExtPtr(RARRAY_PTR(ary)[i]);
if (!X509_add_ext(x509, ext, -1)) { /* DUPs ext - FREE it */
X509_EXTENSION_free(ext);
ossl_raise(eX509CertError, NULL);
}
X509_EXTENSION_free(ext);
}
return ary;
}
|
#inspect ⇒ Object
707 708 709 710 711 712 713 714 715 716 717 718 719 |
# File 'ossl_x509cert.c', line 707
static VALUE
ossl_x509_inspect(VALUE self)
{
return rb_sprintf("#<%"PRIsVALUE": subject=%+"PRIsVALUE", "
"issuer=%+"PRIsVALUE", serial=%+"PRIsVALUE", "
"not_before=%+"PRIsVALUE", not_after=%+"PRIsVALUE">",
rb_obj_class(self),
ossl_x509_get_subject(self),
ossl_x509_get_issuer(self),
ossl_x509_get_serial(self),
ossl_x509_get_not_before(self),
ossl_x509_get_not_after(self));
}
|
#issuer ⇒ Object
419 420 421 422 423 424 425 426 427 428 429 430 431 |
# File 'ossl_x509cert.c', line 419
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);
}
|
#issuer=(name) ⇒ Object
437 438 439 440 441 442 443 444 445 446 447 448 |
# File 'ossl_x509cert.c', line 437
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;
}
|
#not_after ⇒ Time
491 492 493 494 495 496 497 498 499 500 501 502 503 |
# File 'ossl_x509cert.c', line 491
static VALUE
ossl_x509_get_not_after(VALUE self)
{
X509 *x509;
ASN1_TIME *asn1time;
GetX509(self, x509);
if (!(asn1time = X509_get_notAfter(x509))) { /* NO DUP - don't free! */
ossl_raise(eX509CertError, NULL);
}
return asn1time_to_time(asn1time);
}
|
#not_after=(time) ⇒ Time
509 510 511 512 513 514 515 516 517 518 519 520 521 522 |
# File 'ossl_x509cert.c', line 509
static VALUE
ossl_x509_set_not_after(VALUE self, VALUE time)
{
X509 *x509;
time_t sec;
sec = time_to_time_t(time);
GetX509(self, x509);
if (!X509_time_adj(X509_get_notAfter(x509), 0, &sec)) {
ossl_raise(eX509CertError, NULL);
}
return time;
}
|
#not_before ⇒ Time
454 455 456 457 458 459 460 461 462 463 464 465 466 |
# File 'ossl_x509cert.c', line 454
static VALUE
ossl_x509_get_not_before(VALUE self)
{
X509 *x509;
ASN1_UTCTIME *asn1time;
GetX509(self, x509);
if (!(asn1time = X509_get_notBefore(x509))) { /* NO DUP - don't free! */
ossl_raise(eX509CertError, NULL);
}
return asn1time_to_time(asn1time);
}
|
#not_before=(time) ⇒ Time
472 473 474 475 476 477 478 479 480 481 482 483 484 485 |
# File 'ossl_x509cert.c', line 472
static VALUE
ossl_x509_set_not_before(VALUE self, VALUE time)
{
X509 *x509;
time_t sec;
sec = time_to_time_t(time);
GetX509(self, x509);
if (!X509_time_adj(X509_get_notBefore(x509), 0, &sec)) {
ossl_raise(eX509CertError, NULL);
}
return time;
}
|
#pretty_print(q) ⇒ Object
170 171 172 173 174 175 176 177 178 179 |
# File 'lib/openssl/x509.rb', line 170 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 |
#public_key ⇒ Object
528 529 530 531 532 533 534 535 536 537 538 539 540 |
# File 'ossl_x509cert.c', line 528
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_new(pkey); /* NO DUP - OK */
}
|
#public_key=(key) ⇒ Object
546 547 548 549 550 551 552 553 554 555 556 557 |
# File 'ossl_x509cert.c', line 546
static VALUE
ossl_x509_set_public_key(VALUE self, VALUE key)
{
X509 *x509;
GetX509(self, x509);
if (!X509_set_pubkey(x509, GetPKeyPtr(key))) { /* DUPs pkey */
ossl_raise(eX509CertError, NULL);
}
return key;
}
|
#serial ⇒ Integer
329 330 331 332 333 334 335 336 337 |
# File 'ossl_x509cert.c', line 329
static VALUE
ossl_x509_get_serial(VALUE self)
{
X509 *x509;
GetX509(self, x509);
return asn1integer_to_num(X509_get_serialNumber(x509));
}
|
#serial=(integer) ⇒ Integer
343 344 345 346 347 348 349 350 351 352 353 354 |
# File 'ossl_x509cert.c', line 343
static VALUE
ossl_x509_set_serial(VALUE self, VALUE num)
{
X509 *x509;
GetX509(self, x509);
x509->cert_info->serialNumber =
num_to_asn1integer(num, X509_get_serialNumber(x509));
return num;
}
|
#sign(key, digest) ⇒ self
563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 |
# File 'ossl_x509cert.c', line 563
static VALUE
ossl_x509_sign(VALUE self, VALUE key, VALUE digest)
{
X509 *x509;
EVP_PKEY *pkey;
const EVP_MD *md;
pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */
md = GetDigestPtr(digest);
GetX509(self, x509);
if (!X509_sign(x509, pkey, md)) {
ossl_raise(eX509CertError, NULL);
}
return self;
}
|
#signature_algorithm ⇒ String
360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 |
# File 'ossl_x509cert.c', line 360
static VALUE
ossl_x509_get_signature_algorithm(VALUE self)
{
X509 *x509;
BIO *out;
VALUE str;
GetX509(self, x509);
out = BIO_new(BIO_s_mem());
if (!out) ossl_raise(eX509CertError, NULL);
if (!i2a_ASN1_OBJECT(out, x509->cert_info->signature->algorithm)) {
BIO_free(out);
ossl_raise(eX509CertError, NULL);
}
str = ossl_membio2str(out);
return str;
}
|
#subject ⇒ Object
384 385 386 387 388 389 390 391 392 393 394 395 396 |
# File 'ossl_x509cert.c', line 384
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);
}
|
#subject=(name) ⇒ Object
402 403 404 405 406 407 408 409 410 411 412 413 |
# File 'ossl_x509cert.c', line 402
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;
}
|
#to_der ⇒ String
199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 |
# File 'ossl_x509cert.c', line 199
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;
}
|
#to_pem ⇒ String Also known as: to_s
223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 |
# File 'ossl_x509cert.c', line 223
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;
}
|
#to_text ⇒ String
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 |
# File 'ossl_x509cert.c', line 247
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;
}
|
#verify(key) ⇒ Object
Checks that cert signature is made with PRIVversion of this PUBLIC ‘key’
586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 |
# File 'ossl_x509cert.c', line 586
static VALUE
ossl_x509_verify(VALUE self, VALUE key)
{
X509 *x509;
EVP_PKEY *pkey;
int i;
pkey = GetPKeyPtr(key); /* NO NEED TO DUP */
GetX509(self, x509);
if ((i = X509_verify(x509, pkey)) < 0) {
ossl_raise(eX509CertError, NULL);
}
if (i > 0) {
return Qtrue;
}
return Qfalse;
}
|
#version ⇒ Integer
294 295 296 297 298 299 300 301 302 |
# File 'ossl_x509cert.c', line 294
static VALUE
ossl_x509_get_version(VALUE self)
{
X509 *x509;
GetX509(self, x509);
return LONG2NUM(X509_get_version(x509));
}
|
#version=(integer) ⇒ Integer
308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 |
# File 'ossl_x509cert.c', line 308
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;
}
|