openssl 2.1.4 → 2.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTING.md +9 -7
  3. data/History.md +100 -0
  4. data/README.md +2 -2
  5. data/ext/openssl/extconf.rb +24 -15
  6. data/ext/openssl/openssl_missing.h +36 -1
  7. data/ext/openssl/ossl.c +58 -25
  8. data/ext/openssl/ossl.h +7 -4
  9. data/ext/openssl/ossl_asn1.c +25 -0
  10. data/ext/openssl/ossl_bn.c +65 -10
  11. data/ext/openssl/ossl_bn.h +2 -1
  12. data/ext/openssl/ossl_cipher.c +33 -24
  13. data/ext/openssl/ossl_digest.c +16 -51
  14. data/ext/openssl/ossl_engine.c +2 -12
  15. data/ext/openssl/ossl_hmac.c +5 -11
  16. data/ext/openssl/ossl_kdf.c +3 -19
  17. data/ext/openssl/ossl_ns_spki.c +1 -1
  18. data/ext/openssl/ossl_ocsp.c +6 -11
  19. data/ext/openssl/ossl_ocsp.h +3 -3
  20. data/ext/openssl/ossl_pkcs7.c +3 -19
  21. data/ext/openssl/ossl_pkcs7.h +16 -0
  22. data/ext/openssl/ossl_pkey.c +180 -14
  23. data/ext/openssl/ossl_pkey_dsa.c +2 -2
  24. data/ext/openssl/ossl_pkey_ec.c +29 -0
  25. data/ext/openssl/ossl_pkey_rsa.c +17 -9
  26. data/ext/openssl/ossl_rand.c +2 -32
  27. data/ext/openssl/ossl_ssl.c +94 -42
  28. data/ext/openssl/ossl_ts.c +1524 -0
  29. data/ext/openssl/ossl_ts.h +16 -0
  30. data/ext/openssl/ossl_x509cert.c +2 -2
  31. data/ext/openssl/ossl_x509ext.c +14 -0
  32. data/ext/openssl/ossl_x509name.c +7 -3
  33. data/lib/openssl/bn.rb +1 -1
  34. data/lib/openssl/buffering.rb +28 -5
  35. data/lib/openssl/cipher.rb +1 -1
  36. data/lib/openssl/config.rb +17 -8
  37. data/lib/openssl/digest.rb +10 -12
  38. data/lib/openssl/hmac.rb +13 -0
  39. data/lib/openssl/marshal.rb +30 -0
  40. data/lib/openssl/pkcs5.rb +1 -1
  41. data/lib/openssl/pkey.rb +18 -1
  42. data/lib/openssl/ssl.rb +40 -2
  43. data/lib/openssl/version.rb +5 -0
  44. data/lib/openssl/x509.rb +155 -1
  45. data/lib/openssl.rb +25 -9
  46. metadata +6 -3
  47. data/ext/openssl/deprecation.rb +0 -27
  48. data/ext/openssl/ossl_version.h +0 -15
@@ -0,0 +1,16 @@
1
+ /*
2
+ *
3
+ * Copyright (C) 2010 Martin Bosslet <Martin.Bosslet@googlemail.com>
4
+ * All rights reserved.
5
+ */
6
+ /*
7
+ * This program is licenced under the same licence as Ruby.
8
+ * (See the file 'LICENCE'.)
9
+ */
10
+
11
+ #if !defined(_OSSL_TS_H_)
12
+ #define _OSSL_TS_H_
13
+
14
+ void Init_ossl_ts(void);
15
+
16
+ #endif
@@ -788,7 +788,7 @@ Init_ossl_x509cert(void)
788
788
  * root_ca.add_extension(ef.create_extension("keyUsage","keyCertSign, cRLSign", true))
789
789
  * root_ca.add_extension(ef.create_extension("subjectKeyIdentifier","hash",false))
790
790
  * root_ca.add_extension(ef.create_extension("authorityKeyIdentifier","keyid:always",false))
791
- * root_ca.sign(root_key, OpenSSL::Digest::SHA256.new)
791
+ * root_ca.sign(root_key, OpenSSL::Digest.new('SHA256'))
792
792
  *
793
793
  * The next step is to create the end-entity certificate using the root CA
794
794
  * certificate.
@@ -807,7 +807,7 @@ Init_ossl_x509cert(void)
807
807
  * ef.issuer_certificate = root_ca
808
808
  * cert.add_extension(ef.create_extension("keyUsage","digitalSignature", true))
809
809
  * cert.add_extension(ef.create_extension("subjectKeyIdentifier","hash",false))
810
- * cert.sign(root_key, OpenSSL::Digest::SHA256.new)
810
+ * cert.sign(root_key, OpenSSL::Digest.new('SHA256'))
811
811
  *
812
812
  */
813
813
  cX509Cert = rb_define_class_under(mX509, "Certificate", rb_cObject);
@@ -402,6 +402,19 @@ ossl_x509ext_get_value(VALUE obj)
402
402
  return ret;
403
403
  }
404
404
 
405
+ static VALUE
406
+ ossl_x509ext_get_value_der(VALUE obj)
407
+ {
408
+ X509_EXTENSION *ext;
409
+ ASN1_OCTET_STRING *value;
410
+
411
+ GetX509Ext(obj, ext);
412
+ if ((value = X509_EXTENSION_get_data(ext)) == NULL)
413
+ ossl_raise(eX509ExtError, NULL);
414
+
415
+ return rb_str_new((const char *)value->data, value->length);
416
+ }
417
+
405
418
  static VALUE
406
419
  ossl_x509ext_get_critical(VALUE obj)
407
420
  {
@@ -472,6 +485,7 @@ Init_ossl_x509ext(void)
472
485
  rb_define_method(cX509Ext, "critical=", ossl_x509ext_set_critical, 1);
473
486
  rb_define_method(cX509Ext, "oid", ossl_x509ext_get_oid, 0);
474
487
  rb_define_method(cX509Ext, "value", ossl_x509ext_get_value, 0);
488
+ rb_define_method(cX509Ext, "value_der", ossl_x509ext_get_value_der, 0);
475
489
  rb_define_method(cX509Ext, "critical?", ossl_x509ext_get_critical, 0);
476
490
  rb_define_method(cX509Ext, "to_der", ossl_x509ext_to_der, 0);
477
491
  }
@@ -387,17 +387,21 @@ ossl_x509name_cmp0(VALUE self, VALUE other)
387
387
 
388
388
  /*
389
389
  * call-seq:
390
- * name.cmp(other) -> -1 | 0 | 1
391
- * name <=> other -> -1 | 0 | 1
390
+ * name.cmp(other) -> -1 | 0 | 1 | nil
391
+ * name <=> other -> -1 | 0 | 1 | nil
392
392
  *
393
393
  * Compares this Name with _other_ and returns +0+ if they are the same and +-1+
394
394
  * or ++1+ if they are greater or less than each other respectively.
395
+ * Returns +nil+ if they are not comparable (i.e. different types).
395
396
  */
396
397
  static VALUE
397
398
  ossl_x509name_cmp(VALUE self, VALUE other)
398
399
  {
399
400
  int result;
400
401
 
402
+ if (!rb_obj_is_kind_of(other, cX509Name))
403
+ return Qnil;
404
+
401
405
  result = ossl_x509name_cmp0(self, other);
402
406
  if (result < 0) return INT2FIX(-1);
403
407
  if (result > 0) return INT2FIX(1);
@@ -494,7 +498,7 @@ ossl_x509name_to_der(VALUE self)
494
498
  * You can create a Name by parsing a distinguished name String or by
495
499
  * supplying the distinguished name as an Array.
496
500
  *
497
- * name = OpenSSL::X509::Name.parse 'CN=nobody/DC=example'
501
+ * name = OpenSSL::X509::Name.parse '/CN=nobody/DC=example'
498
502
  *
499
503
  * name = OpenSSL::X509::Name.new [['CN', 'nobody'], ['DC', 'example']]
500
504
  */
data/lib/openssl/bn.rb CHANGED
@@ -1,4 +1,4 @@
1
- # frozen_string_literal: false
1
+ # frozen_string_literal: true
2
2
  #--
3
3
  #
4
4
  # = Ruby-space definitions that completes C-space funcs for BN
@@ -1,5 +1,5 @@
1
1
  # coding: binary
2
- # frozen_string_literal: false
2
+ # frozen_string_literal: true
3
3
  #--
4
4
  #= Info
5
5
  # 'OpenSSL for Ruby 2' project
@@ -22,6 +22,29 @@
22
22
  module OpenSSL::Buffering
23
23
  include Enumerable
24
24
 
25
+ # A buffer which will retain binary encoding.
26
+ class Buffer < String
27
+ BINARY = Encoding::BINARY
28
+
29
+ def initialize
30
+ super
31
+
32
+ force_encoding(BINARY)
33
+ end
34
+
35
+ def << string
36
+ if string.encoding == BINARY
37
+ super(string)
38
+ else
39
+ super(string.b)
40
+ end
41
+
42
+ return self
43
+ end
44
+
45
+ alias concat <<
46
+ end
47
+
25
48
  ##
26
49
  # The "sync mode" of the SSLSocket.
27
50
  #
@@ -40,7 +63,7 @@ module OpenSSL::Buffering
40
63
  def initialize(*)
41
64
  super
42
65
  @eof = false
43
- @rbuffer = ""
66
+ @rbuffer = Buffer.new
44
67
  @sync = @io.sync
45
68
  end
46
69
 
@@ -312,7 +335,7 @@ module OpenSSL::Buffering
312
335
  # buffer is flushed to the underlying socket.
313
336
 
314
337
  def do_write(s)
315
- @wbuffer = "" unless defined? @wbuffer
338
+ @wbuffer = Buffer.new unless defined? @wbuffer
316
339
  @wbuffer << s
317
340
  @wbuffer.force_encoding(Encoding::BINARY)
318
341
  @sync ||= false
@@ -398,7 +421,7 @@ module OpenSSL::Buffering
398
421
  # See IO#puts for full details.
399
422
 
400
423
  def puts(*args)
401
- s = ""
424
+ s = Buffer.new
402
425
  if args.empty?
403
426
  s << "\n"
404
427
  end
@@ -416,7 +439,7 @@ module OpenSSL::Buffering
416
439
  # See IO#print for full details.
417
440
 
418
441
  def print(*args)
419
- s = ""
442
+ s = Buffer.new
420
443
  args.each{ |arg| s << arg.to_s }
421
444
  do_write(s)
422
445
  nil
@@ -1,4 +1,4 @@
1
- # frozen_string_literal: false
1
+ # frozen_string_literal: true
2
2
  #--
3
3
  # = Ruby-space predefined Cipher subclasses
4
4
  #
@@ -1,4 +1,4 @@
1
- # frozen_string_literal: false
1
+ # frozen_string_literal: true
2
2
  =begin
3
3
  = Ruby-space definitions that completes C-space funcs for Config
4
4
 
@@ -37,7 +37,7 @@ module OpenSSL
37
37
  def parse(string)
38
38
  c = new()
39
39
  parse_config(StringIO.new(string)).each do |section, hash|
40
- c[section] = hash
40
+ c.set_section(section, hash)
41
41
  end
42
42
  c
43
43
  end
@@ -53,9 +53,8 @@ module OpenSSL
53
53
  def parse_config(io)
54
54
  begin
55
55
  parse_config_lines(io)
56
- rescue ConfigError => e
57
- e.message.replace("error in line #{io.lineno}: " + e.message)
58
- raise
56
+ rescue => error
57
+ raise ConfigError, "error in line #{io.lineno}: " + error.message
59
58
  end
60
59
  end
61
60
 
@@ -267,7 +266,7 @@ module OpenSSL
267
266
  if filename
268
267
  File.open(filename.to_s) do |file|
269
268
  Config.parse_config(file).each do |section, hash|
270
- self[section] = hash
269
+ set_section(section, hash)
271
270
  end
272
271
  end
273
272
  end
@@ -316,6 +315,8 @@ module OpenSSL
316
315
  end
317
316
 
318
317
  ##
318
+ # *Deprecated in v2.2.0*. This method will be removed in a future release.
319
+ #
319
320
  # Set the target _key_ with a given _value_ under a specific _section_.
320
321
  #
321
322
  # Given the following configurating file being loaded:
@@ -370,6 +371,8 @@ module OpenSSL
370
371
  end
371
372
 
372
373
  ##
374
+ # *Deprecated in v2.2.0*. This method will be removed in a future release.
375
+ #
373
376
  # Sets a specific _section_ name with a Hash _pairs_.
374
377
  #
375
378
  # Given the following configuration being created:
@@ -395,9 +398,13 @@ module OpenSSL
395
398
  #
396
399
  def []=(section, pairs)
397
400
  check_modify
398
- @data[section] ||= {}
401
+ set_section(section, pairs)
402
+ end
403
+
404
+ def set_section(section, pairs) # :nodoc:
405
+ hash = @data[section] ||= {}
399
406
  pairs.each do |key, value|
400
- self.add_value(section, key, value)
407
+ hash[key] = value
401
408
  end
402
409
  end
403
410
 
@@ -482,6 +489,8 @@ module OpenSSL
482
489
  end
483
490
 
484
491
  def check_modify
492
+ warn "#{caller(2, 1)[0]}: warning: do not modify OpenSSL::Config; this " \
493
+ "method is deprecated and will be removed in a future release."
485
494
  raise TypeError.new("Insecure: can't modify OpenSSL config") if frozen?
486
495
  end
487
496
 
@@ -1,4 +1,4 @@
1
- # frozen_string_literal: false
1
+ # frozen_string_literal: true
2
2
  #--
3
3
  # = Ruby-space predefined Digest subclasses
4
4
  #
@@ -15,11 +15,6 @@
15
15
  module OpenSSL
16
16
  class Digest
17
17
 
18
- alg = %w(MD2 MD4 MD5 MDC2 RIPEMD160 SHA1 SHA224 SHA256 SHA384 SHA512)
19
- if OPENSSL_VERSION_NUMBER < 0x10100000
20
- alg += %w(DSS DSS1 SHA)
21
- end
22
-
23
18
  # Return the hash value computed with _name_ Digest. _name_ is either the
24
19
  # long name or short name of a supported digest algorithm.
25
20
  #
@@ -29,23 +24,26 @@ module OpenSSL
29
24
  #
30
25
  # which is equivalent to:
31
26
  #
32
- # OpenSSL::Digest::SHA256.digest("abc")
27
+ # OpenSSL::Digest.digest('SHA256', "abc")
33
28
 
34
29
  def self.digest(name, data)
35
30
  super(data, name)
36
31
  end
37
32
 
38
- alg.each{|name|
33
+ %w(MD4 MD5 RIPEMD160 SHA1 SHA224 SHA256 SHA384 SHA512).each do |name|
39
34
  klass = Class.new(self) {
40
35
  define_method(:initialize, ->(data = nil) {super(name, data)})
41
36
  }
37
+
42
38
  singleton = (class << klass; self; end)
39
+
43
40
  singleton.class_eval{
44
- define_method(:digest){|data| new.digest(data) }
45
- define_method(:hexdigest){|data| new.hexdigest(data) }
41
+ define_method(:digest) {|data| new.digest(data)}
42
+ define_method(:hexdigest) {|data| new.hexdigest(data)}
46
43
  }
47
- const_set(name, klass)
48
- }
44
+
45
+ const_set(name.tr('-', '_'), klass)
46
+ end
49
47
 
50
48
  # Deprecated.
51
49
  #
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenSSL
4
+ class HMAC
5
+ # Securely compare with another HMAC instance in constant time.
6
+ def ==(other)
7
+ return false unless HMAC === other
8
+ return false unless self.digest.bytesize == other.digest.bytesize
9
+
10
+ OpenSSL.fixed_length_secure_compare(self.digest, other.digest)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+ #--
3
+ # = Ruby-space definitions to add DER (de)serialization to classes
4
+ #
5
+ # = Info
6
+ # 'OpenSSL for Ruby 2' project
7
+ # Copyright (C) 2002 Michal Rokos <m.rokos@sh.cvut.cz>
8
+ # All rights reserved.
9
+ #
10
+ # = Licence
11
+ # This program is licensed under the same licence as Ruby.
12
+ # (See the file 'LICENCE'.)
13
+ #++
14
+ module OpenSSL
15
+ module Marshal
16
+ def self.included(base)
17
+ base.extend(ClassMethods)
18
+ end
19
+
20
+ module ClassMethods
21
+ def _load(string)
22
+ new(string)
23
+ end
24
+ end
25
+
26
+ def _dump(_level)
27
+ to_der
28
+ end
29
+ end
30
+ end
data/lib/openssl/pkcs5.rb CHANGED
@@ -1,4 +1,4 @@
1
- # frozen_string_literal: false
1
+ # frozen_string_literal: true
2
2
  #--
3
3
  # Ruby/OpenSSL Project
4
4
  # Copyright (C) 2017 Ruby/OpenSSL Project Authors
data/lib/openssl/pkey.rb CHANGED
@@ -1,11 +1,24 @@
1
- # frozen_string_literal: false
1
+ # frozen_string_literal: true
2
2
  #--
3
3
  # Ruby/OpenSSL Project
4
4
  # Copyright (C) 2017 Ruby/OpenSSL Project Authors
5
5
  #++
6
6
 
7
+ require_relative 'marshal'
8
+
7
9
  module OpenSSL::PKey
10
+ class DH
11
+ include OpenSSL::Marshal
12
+ end
13
+
14
+ class DSA
15
+ include OpenSSL::Marshal
16
+ end
17
+
8
18
  if defined?(EC)
19
+ class EC
20
+ include OpenSSL::Marshal
21
+ end
9
22
  class EC::Point
10
23
  # :call-seq:
11
24
  # point.to_bn([conversion_form]) -> OpenSSL::BN
@@ -22,4 +35,8 @@ module OpenSSL::PKey
22
35
  end
23
36
  end
24
37
  end
38
+
39
+ class RSA
40
+ include OpenSSL::Marshal
41
+ end
25
42
  end
data/lib/openssl/ssl.rb CHANGED
@@ -1,4 +1,4 @@
1
- # frozen_string_literal: false
1
+ # frozen_string_literal: true
2
2
  =begin
3
3
  = Info
4
4
  'OpenSSL for Ruby 2' project
@@ -13,6 +13,7 @@
13
13
  require "openssl/buffering"
14
14
  require "io/nonblock"
15
15
  require "ipaddr"
16
+ require "socket"
16
17
 
17
18
  module OpenSSL
18
19
  module SSL
@@ -231,6 +232,11 @@ YoaOffgTf5qxiwkjnlVZQc3whgnEt9FpVMvQ9eknyeGB5KHfayAc3+hUAvI3/Cr3
231
232
  end
232
233
 
233
234
  module SocketForwarder
235
+ # The file descriptor for the socket.
236
+ def fileno
237
+ to_io.fileno
238
+ end
239
+
234
240
  def addr
235
241
  to_io.addr
236
242
  end
@@ -435,6 +441,38 @@ YoaOffgTf5qxiwkjnlVZQc3whgnEt9FpVMvQ9eknyeGB5KHfayAc3+hUAvI3/Cr3
435
441
  def session_get_cb
436
442
  @context.session_get_cb
437
443
  end
444
+
445
+ class << self
446
+
447
+ # call-seq:
448
+ # open(remote_host, remote_port, local_host=nil, local_port=nil, context: nil)
449
+ #
450
+ # Creates a new instance of SSLSocket.
451
+ # _remote\_host_ and _remote\_port_ are used to open TCPSocket.
452
+ # If _local\_host_ and _local\_port_ are specified,
453
+ # then those parameters are used on the local end to establish the connection.
454
+ # If _context_ is provided,
455
+ # the SSL Sockets initial params will be taken from the context.
456
+ #
457
+ # === Examples
458
+ #
459
+ # sock = OpenSSL::SSL::SSLSocket.open('localhost', 443)
460
+ # sock.connect # Initiates a connection to localhost:443
461
+ #
462
+ # with SSLContext:
463
+ #
464
+ # ctx = OpenSSL::SSL::SSLContext.new
465
+ # sock = OpenSSL::SSL::SSLSocket.open('localhost', 443, context: ctx)
466
+ # sock.connect # Initiates a connection to localhost:443 with SSLContext
467
+ def open(remote_host, remote_port, local_host=nil, local_port=nil, context: nil)
468
+ sock = ::TCPSocket.open(remote_host, remote_port, local_host, local_port)
469
+ if context.nil?
470
+ return OpenSSL::SSL::SSLSocket.new(sock)
471
+ else
472
+ return OpenSSL::SSL::SSLSocket.new(sock, context)
473
+ end
474
+ end
475
+ end
438
476
  end
439
477
 
440
478
  ##
@@ -465,7 +503,7 @@ YoaOffgTf5qxiwkjnlVZQc3whgnEt9FpVMvQ9eknyeGB5KHfayAc3+hUAvI3/Cr3
465
503
  end
466
504
 
467
505
  # See TCPServer#listen for details.
468
- def listen(backlog=5)
506
+ def listen(backlog=Socket::SOMAXCONN)
469
507
  @svr.listen(backlog)
470
508
  end
471
509
 
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenSSL
4
+ VERSION = "2.2.2"
5
+ end
data/lib/openssl/x509.rb CHANGED
@@ -1,4 +1,4 @@
1
- # frozen_string_literal: false
1
+ # frozen_string_literal: true
2
2
  #--
3
3
  # = Ruby-space definitions that completes C-space funcs for X509 and subclasses
4
4
  #
@@ -12,6 +12,8 @@
12
12
  # (See the file 'LICENCE'.)
13
13
  #++
14
14
 
15
+ require_relative 'marshal'
16
+
15
17
  module OpenSSL
16
18
  module X509
17
19
  class ExtensionFactory
@@ -41,6 +43,8 @@ module OpenSSL
41
43
  end
42
44
 
43
45
  class Extension
46
+ include OpenSSL::Marshal
47
+
44
48
  def ==(other)
45
49
  return false unless Extension === other
46
50
  to_der == other.to_der
@@ -60,9 +64,146 @@ module OpenSSL
60
64
  def to_a
61
65
  [ self.oid, self.value, self.critical? ]
62
66
  end
67
+
68
+ module Helpers
69
+ def find_extension(oid)
70
+ extensions.find { |e| e.oid == oid }
71
+ end
72
+ end
73
+
74
+ module SubjectKeyIdentifier
75
+ include Helpers
76
+
77
+ # Get the subject's key identifier from the subjectKeyIdentifier
78
+ # exteension, as described in RFC5280 Section 4.2.1.2.
79
+ #
80
+ # Returns the binary String key identifier or nil or raises
81
+ # ASN1::ASN1Error.
82
+ def subject_key_identifier
83
+ ext = find_extension("subjectKeyIdentifier")
84
+ return nil if ext.nil?
85
+
86
+ ski_asn1 = ASN1.decode(ext.value_der)
87
+ if ext.critical? || ski_asn1.tag_class != :UNIVERSAL || ski_asn1.tag != ASN1::OCTET_STRING
88
+ raise ASN1::ASN1Error, "invalid extension"
89
+ end
90
+
91
+ ski_asn1.value
92
+ end
93
+ end
94
+
95
+ module AuthorityKeyIdentifier
96
+ include Helpers
97
+
98
+ # Get the issuing certificate's key identifier from the
99
+ # authorityKeyIdentifier extension, as described in RFC5280
100
+ # Section 4.2.1.1
101
+ #
102
+ # Returns the binary String keyIdentifier or nil or raises
103
+ # ASN1::ASN1Error.
104
+ def authority_key_identifier
105
+ ext = find_extension("authorityKeyIdentifier")
106
+ return nil if ext.nil?
107
+
108
+ aki_asn1 = ASN1.decode(ext.value_der)
109
+ if ext.critical? || aki_asn1.tag_class != :UNIVERSAL || aki_asn1.tag != ASN1::SEQUENCE
110
+ raise ASN1::ASN1Error, "invalid extension"
111
+ end
112
+
113
+ key_id = aki_asn1.value.find do |v|
114
+ v.tag_class == :CONTEXT_SPECIFIC && v.tag == 0
115
+ end
116
+
117
+ key_id.nil? ? nil : key_id.value
118
+ end
119
+ end
120
+
121
+ module CRLDistributionPoints
122
+ include Helpers
123
+
124
+ # Get the distributionPoint fullName URI from the certificate's CRL
125
+ # distribution points extension, as described in RFC5280 Section
126
+ # 4.2.1.13
127
+ #
128
+ # Returns an array of strings or nil or raises ASN1::ASN1Error.
129
+ def crl_uris
130
+ ext = find_extension("crlDistributionPoints")
131
+ return nil if ext.nil?
132
+
133
+ cdp_asn1 = ASN1.decode(ext.value_der)
134
+ if cdp_asn1.tag_class != :UNIVERSAL || cdp_asn1.tag != ASN1::SEQUENCE
135
+ raise ASN1::ASN1Error, "invalid extension"
136
+ end
137
+
138
+ crl_uris = cdp_asn1.map do |crl_distribution_point|
139
+ distribution_point = crl_distribution_point.value.find do |v|
140
+ v.tag_class == :CONTEXT_SPECIFIC && v.tag == 0
141
+ end
142
+ full_name = distribution_point&.value&.find do |v|
143
+ v.tag_class == :CONTEXT_SPECIFIC && v.tag == 0
144
+ end
145
+ full_name&.value&.find do |v|
146
+ v.tag_class == :CONTEXT_SPECIFIC && v.tag == 6 # uniformResourceIdentifier
147
+ end
148
+ end
149
+
150
+ crl_uris&.map(&:value)
151
+ end
152
+ end
153
+
154
+ module AuthorityInfoAccess
155
+ include Helpers
156
+
157
+ # Get the information and services for the issuer from the certificate's
158
+ # authority information access extension exteension, as described in RFC5280
159
+ # Section 4.2.2.1.
160
+ #
161
+ # Returns an array of strings or nil or raises ASN1::ASN1Error.
162
+ def ca_issuer_uris
163
+ aia_asn1 = parse_aia_asn1
164
+ return nil if aia_asn1.nil?
165
+
166
+ ca_issuer = aia_asn1.value.select do |authority_info_access|
167
+ authority_info_access.value.first.value == "caIssuers"
168
+ end
169
+
170
+ ca_issuer&.map(&:value)&.map(&:last)&.map(&:value)
171
+ end
172
+
173
+ # Get the URIs for OCSP from the certificate's authority information access
174
+ # extension exteension, as described in RFC5280 Section 4.2.2.1.
175
+ #
176
+ # Returns an array of strings or nil or raises ASN1::ASN1Error.
177
+ def ocsp_uris
178
+ aia_asn1 = parse_aia_asn1
179
+ return nil if aia_asn1.nil?
180
+
181
+ ocsp = aia_asn1.value.select do |authority_info_access|
182
+ authority_info_access.value.first.value == "OCSP"
183
+ end
184
+
185
+ ocsp&.map(&:value)&.map(&:last)&.map(&:value)
186
+ end
187
+
188
+ private
189
+
190
+ def parse_aia_asn1
191
+ ext = find_extension("authorityInfoAccess")
192
+ return nil if ext.nil?
193
+
194
+ aia_asn1 = ASN1.decode(ext.value_der)
195
+ if ext.critical? || aia_asn1.tag_class != :UNIVERSAL || aia_asn1.tag != ASN1::SEQUENCE
196
+ raise ASN1::ASN1Error, "invalid extension"
197
+ end
198
+
199
+ aia_asn1
200
+ end
201
+ end
63
202
  end
64
203
 
65
204
  class Name
205
+ include OpenSSL::Marshal
206
+
66
207
  module RFC2253DN
67
208
  Special = ',=+<>#;'
68
209
  HexChar = /[0-9a-fA-F]/
@@ -166,6 +307,8 @@ module OpenSSL
166
307
  end
167
308
 
168
309
  class Attribute
310
+ include OpenSSL::Marshal
311
+
169
312
  def ==(other)
170
313
  return false unless Attribute === other
171
314
  to_der == other.to_der
@@ -179,6 +322,12 @@ module OpenSSL
179
322
  end
180
323
 
181
324
  class Certificate
325
+ include OpenSSL::Marshal
326
+ include Extension::SubjectKeyIdentifier
327
+ include Extension::AuthorityKeyIdentifier
328
+ include Extension::CRLDistributionPoints
329
+ include Extension::AuthorityInfoAccess
330
+
182
331
  def pretty_print(q)
183
332
  q.object_group(self) {
184
333
  q.breakable
@@ -192,6 +341,9 @@ module OpenSSL
192
341
  end
193
342
 
194
343
  class CRL
344
+ include OpenSSL::Marshal
345
+ include Extension::AuthorityKeyIdentifier
346
+
195
347
  def ==(other)
196
348
  return false unless CRL === other
197
349
  to_der == other.to_der
@@ -206,6 +358,8 @@ module OpenSSL
206
358
  end
207
359
 
208
360
  class Request
361
+ include OpenSSL::Marshal
362
+
209
363
  def ==(other)
210
364
  return false unless Request === other
211
365
  to_der == other.to_der