Class: OpenSSL::X509::Certificate
- Inherits:
-
Object
- Object
- OpenSSL::X509::Certificate
- Defined in:
- ext/rubysl/openssl/ossl_x509cert.c,
lib/openssl/x509.rb,
ext/rubysl/openssl/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
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 |
# File 'ext/rubysl/openssl/ossl_x509cert.c', line 152
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
694 695 696 697 698 699 700 701 702 703 704 705 706 707 |
# File 'ext/rubysl/openssl/ossl_x509cert.c', line 694
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;
}
|
#check_private_key(key) ⇒ Object
Checks if ‘key’ is PRIV key for this cert
618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 |
# File 'ext/rubysl/openssl/ossl_x509cert.c', line 618
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;
}
|
#extensions ⇒ Array
639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 |
# File 'ext/rubysl/openssl/ossl_x509cert.c', line 639
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
665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 |
# File 'ext/rubysl/openssl/ossl_x509cert.c', line 665
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);
while ((ext = X509_delete_ext(x509, 0)))
X509_EXTENSION_free(ext);
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, NULL);
}
}
return ary;
}
|
#inspect ⇒ Object
709 710 711 712 713 714 715 716 717 718 719 720 721 |
# File 'ext/rubysl/openssl/ossl_x509cert.c', line 709
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
420 421 422 423 424 425 426 427 428 429 430 431 432 |
# File 'ext/rubysl/openssl/ossl_x509cert.c', line 420
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
438 439 440 441 442 443 444 445 446 447 448 449 |
# File 'ext/rubysl/openssl/ossl_x509cert.c', line 438
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
494 495 496 497 498 499 500 501 502 503 504 505 506 |
# File 'ext/rubysl/openssl/ossl_x509cert.c', line 494
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);
}
|
#not_after=(time) ⇒ Time
512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 |
# File 'ext/rubysl/openssl/ossl_x509cert.c', line 512
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_set_notAfter(x509, asn1time)) {
ASN1_TIME_free(asn1time);
ossl_raise(eX509CertError, "X509_set_notAfter");
}
ASN1_TIME_free(asn1time);
return time;
}
|
#not_before ⇒ Time
455 456 457 458 459 460 461 462 463 464 465 466 467 |
# File 'ext/rubysl/openssl/ossl_x509cert.c', line 455
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);
}
|
#not_before=(time) ⇒ Time
473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 |
# File 'ext/rubysl/openssl/ossl_x509cert.c', line 473
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_set_notBefore(x509, asn1time)) {
ASN1_TIME_free(asn1time);
ossl_raise(eX509CertError, "X509_set_notBefore");
}
ASN1_TIME_free(asn1time);
return time;
}
|
#pretty_print(q) ⇒ Object
164 165 166 167 168 169 170 171 172 173 |
# File 'lib/openssl/x509.rb', line 164 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
533 534 535 536 537 538 539 540 541 542 543 544 545 |
# File 'ext/rubysl/openssl/ossl_x509cert.c', line 533
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
551 552 553 554 555 556 557 558 559 560 561 562 563 |
# File 'ext/rubysl/openssl/ossl_x509cert.c', line 551
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;
}
|
#serial ⇒ Integer
332 333 334 335 336 337 338 339 340 |
# File 'ext/rubysl/openssl/ossl_x509cert.c', line 332
static VALUE
ossl_x509_get_serial(VALUE self)
{
X509 *x509;
GetX509(self, x509);
return asn1integer_to_num(X509_get_serialNumber(x509));
}
|
#serial=(integer) ⇒ Integer
346 347 348 349 350 351 352 353 354 355 |
# File 'ext/rubysl/openssl/ossl_x509cert.c', line 346
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;
}
|
#sign(key, digest) ⇒ self
569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 |
# File 'ext/rubysl/openssl/ossl_x509cert.c', line 569
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
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 |
# File 'ext/rubysl/openssl/ossl_x509cert.c', line 361
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_get0_tbs_sigalg(x509)->algorithm)) {
BIO_free(out);
ossl_raise(eX509CertError, NULL);
}
str = ossl_membio2str(out);
return str;
}
|
#subject ⇒ Object
385 386 387 388 389 390 391 392 393 394 395 396 397 |
# File 'ext/rubysl/openssl/ossl_x509cert.c', line 385
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
403 404 405 406 407 408 409 410 411 412 413 414 |
# File 'ext/rubysl/openssl/ossl_x509cert.c', line 403
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
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 |
# File 'ext/rubysl/openssl/ossl_x509cert.c', line 202
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
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 |
# File 'ext/rubysl/openssl/ossl_x509cert.c', line 226
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
250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 |
# File 'ext/rubysl/openssl/ossl_x509cert.c', line 250
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’
592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 |
# File 'ext/rubysl/openssl/ossl_x509cert.c', line 592
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);
}
}
|
#version ⇒ Integer
297 298 299 300 301 302 303 304 305 |
# File 'ext/rubysl/openssl/ossl_x509cert.c', line 297
static VALUE
ossl_x509_get_version(VALUE self)
{
X509 *x509;
GetX509(self, x509);
return LONG2NUM(X509_get_version(x509));
}
|
#version=(integer) ⇒ Integer
311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 |
# File 'ext/rubysl/openssl/ossl_x509cert.c', line 311
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;
}
|