r509 0.8.1 → 0.9

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 (203) hide show
  1. data/README.md +343 -151
  2. data/Rakefile +26 -23
  3. data/bin/r509 +126 -112
  4. data/bin/r509-parse +24 -24
  5. data/doc/R509.html +169 -7
  6. data/doc/R509/ASN1.html +370 -0
  7. data/doc/R509/ASN1/GeneralName.html +1121 -0
  8. data/doc/R509/ASN1/GeneralNames.html +843 -0
  9. data/doc/R509/ASN1/NoticeReference.html +392 -0
  10. data/doc/R509/ASN1/PolicyInformation.html +387 -0
  11. data/doc/R509/ASN1/PolicyQualifiers.html +455 -0
  12. data/doc/R509/ASN1/UserNotice.html +386 -0
  13. data/doc/R509/{Crl.html → CRL.html} +7 -7
  14. data/doc/R509/CRL/Administrator.html +1559 -0
  15. data/doc/R509/{Crl/Parser.html → CRL/SignedList.html} +501 -210
  16. data/doc/R509/{Csr.html → CSR.html} +444 -314
  17. data/doc/R509/Cert.html +866 -617
  18. data/doc/R509/Cert/Extensions.html +52 -41
  19. data/doc/R509/Cert/Extensions/AuthorityInfoAccess.html +70 -35
  20. data/doc/R509/Cert/Extensions/AuthorityKeyIdentifier.html +387 -4
  21. data/doc/R509/Cert/Extensions/BasicConstraints.html +61 -25
  22. data/doc/R509/Cert/Extensions/CRLDistributionPoints.html +354 -0
  23. data/doc/R509/Cert/Extensions/CertificatePolicies.html +340 -0
  24. data/doc/R509/Cert/Extensions/ExtendedKeyUsage.html +440 -49
  25. data/doc/R509/Cert/Extensions/{CrlDistributionPoints.html → InhibitAnyPolicy.html} +52 -35
  26. data/doc/R509/Cert/Extensions/KeyUsage.html +247 -121
  27. data/doc/R509/Cert/Extensions/NameConstraints.html +445 -0
  28. data/doc/R509/Cert/Extensions/OCSPNoCheck.html +239 -0
  29. data/doc/R509/Cert/Extensions/PolicyConstraints.html +424 -0
  30. data/doc/R509/Cert/Extensions/SubjectAlternativeName.html +437 -62
  31. data/doc/R509/Cert/Extensions/SubjectKeyIdentifier.html +52 -10
  32. data/doc/R509/CertificateAuthority.html +4 -4
  33. data/doc/R509/CertificateAuthority/Signer.html +154 -187
  34. data/doc/R509/Config.html +6 -6
  35. data/doc/R509/Config/{CaConfig.html → CAConfig.html} +451 -348
  36. data/doc/R509/Config/{CaConfigPool.html → CAConfigPool.html} +47 -47
  37. data/doc/R509/Config/CAProfile.html +1015 -0
  38. data/doc/R509/Config/SubjectItemPolicy.html +86 -86
  39. data/doc/R509/IOHelpers.html +22 -22
  40. data/doc/R509/MessageDigest.html +14 -14
  41. data/doc/R509/NameSanitizer.html +53 -53
  42. data/doc/R509/{Ocsp.html → OCSP.html} +9 -9
  43. data/doc/R509/{Ocsp → OCSP}/Request.html +7 -7
  44. data/doc/R509/{Ocsp → OCSP}/Request/Nonce.html +56 -11
  45. data/doc/R509/{Ocsp → OCSP}/Response.html +44 -44
  46. data/doc/R509/{OidMapper.html → OIDMapper.html} +23 -39
  47. data/doc/R509/PrivateKey.html +415 -168
  48. data/doc/R509/R509Error.html +3 -3
  49. data/doc/R509/{Spki.html → SPKI.html} +354 -192
  50. data/doc/R509/Subject.html +224 -113
  51. data/doc/R509/Validity.html +27 -5
  52. data/doc/R509/Validity/Checker.html +13 -13
  53. data/doc/R509/Validity/DefaultChecker.html +13 -13
  54. data/doc/R509/Validity/DefaultWriter.html +14 -14
  55. data/doc/R509/Validity/Status.html +39 -39
  56. data/doc/R509/Validity/Writer.html +18 -18
  57. data/doc/_index.html +138 -35
  58. data/doc/class_list.html +1 -1
  59. data/doc/css/style.css +10 -0
  60. data/doc/file.README.html +368 -171
  61. data/doc/file.r509.html +92 -69
  62. data/doc/frames.html +1 -1
  63. data/doc/index.html +368 -171
  64. data/doc/method_list.html +910 -390
  65. data/doc/top-level-namespace.html +3 -3
  66. data/lib/r509.rb +32 -16
  67. data/lib/r509/asn1.rb +375 -0
  68. data/lib/r509/cert.rb +381 -364
  69. data/lib/r509/cert/extensions.rb +443 -76
  70. data/lib/r509/certificate_authority.rb +407 -0
  71. data/lib/r509/config.rb +547 -351
  72. data/lib/r509/crl.rb +336 -366
  73. data/lib/r509/csr.rb +278 -289
  74. data/lib/r509/ec-hack.rb +37 -0
  75. data/lib/r509/exceptions.rb +3 -3
  76. data/lib/r509/io_helpers.rb +44 -44
  77. data/lib/r509/message_digest.rb +53 -0
  78. data/lib/r509/ocsp.rb +80 -70
  79. data/lib/r509/oid_mapper.rb +32 -0
  80. data/lib/r509/private_key.rb +228 -0
  81. data/lib/r509/spki.rb +145 -93
  82. data/lib/r509/subject.rb +203 -110
  83. data/lib/r509/validity.rb +70 -68
  84. data/lib/r509/version.rb +2 -2
  85. data/r509.yaml +92 -69
  86. data/spec/asn1_spec.rb +402 -0
  87. data/spec/cert/extensions_spec.rb +957 -494
  88. data/spec/cert_spec.rb +382 -307
  89. data/spec/certificate_authority_spec.rb +668 -250
  90. data/spec/config_spec.rb +515 -302
  91. data/spec/crl_spec.rb +197 -198
  92. data/spec/csr_spec.rb +334 -289
  93. data/spec/fixtures.rb +247 -171
  94. data/spec/fixtures/cert1.der +0 -0
  95. data/spec/fixtures/cert1.pem +0 -0
  96. data/spec/fixtures/cert1_public_key_modulus.txt +0 -0
  97. data/spec/fixtures/cert3.p12 +0 -0
  98. data/spec/fixtures/cert3.pem +0 -0
  99. data/spec/fixtures/cert3_key.pem +0 -0
  100. data/spec/fixtures/cert3_key_des3.pem +0 -0
  101. data/spec/fixtures/cert4.pem +0 -0
  102. data/spec/fixtures/cert5.pem +0 -0
  103. data/spec/fixtures/cert6.pem +0 -0
  104. data/spec/fixtures/cert_expired.pem +0 -0
  105. data/spec/fixtures/cert_inhibit.pem +24 -0
  106. data/spec/fixtures/cert_name_constraints.pem +29 -0
  107. data/spec/fixtures/cert_not_yet_valid.pem +0 -0
  108. data/spec/fixtures/cert_ocsp_no_check.pem +18 -0
  109. data/spec/fixtures/cert_policy_constraints.pem +31 -0
  110. data/spec/fixtures/cert_san.pem +0 -0
  111. data/spec/fixtures/cert_san2.pem +0 -0
  112. data/spec/fixtures/cert_unknown_extension.pem +28 -0
  113. data/spec/fixtures/config_pool_test_minimal.yaml +11 -11
  114. data/spec/fixtures/config_test.yaml +54 -36
  115. data/spec/fixtures/config_test_dsa.yaml +35 -0
  116. data/spec/fixtures/config_test_ec.yaml +35 -0
  117. data/spec/fixtures/config_test_engine_key.yaml +5 -5
  118. data/spec/fixtures/config_test_engine_no_key_name.yaml +4 -4
  119. data/spec/fixtures/config_test_minimal.yaml +4 -4
  120. data/spec/fixtures/config_test_password.yaml +5 -5
  121. data/spec/fixtures/config_test_various.yaml +111 -74
  122. data/spec/fixtures/crl_list_file.txt +0 -0
  123. data/spec/fixtures/crl_with_reason.pem +0 -0
  124. data/spec/fixtures/csr1.der +0 -0
  125. data/spec/fixtures/csr1.pem +0 -0
  126. data/spec/fixtures/csr1_key.der +0 -0
  127. data/spec/fixtures/csr1_key.pem +0 -0
  128. data/spec/fixtures/csr1_key_encrypted_des3.pem +0 -0
  129. data/spec/fixtures/csr1_newlines.pem +0 -0
  130. data/spec/fixtures/csr1_no_begin_end.pem +0 -0
  131. data/spec/fixtures/csr1_public_key_modulus.txt +0 -0
  132. data/spec/fixtures/csr2.pem +0 -0
  133. data/spec/fixtures/csr2_key.pem +0 -0
  134. data/spec/fixtures/csr3.pem +0 -0
  135. data/spec/fixtures/csr4.pem +0 -0
  136. data/spec/fixtures/csr_dsa.pem +0 -0
  137. data/spec/fixtures/csr_invalid_signature.pem +0 -0
  138. data/spec/fixtures/dsa_key.pem +0 -0
  139. data/spec/fixtures/dsa_root.cer +28 -0
  140. data/spec/fixtures/dsa_root.key +20 -0
  141. data/spec/fixtures/ec_csr2.der +0 -0
  142. data/spec/fixtures/ec_csr2.pem +8 -0
  143. data/spec/fixtures/ec_key1.der +0 -0
  144. data/spec/fixtures/ec_key1.pem +6 -0
  145. data/spec/fixtures/ec_key1_encrypted.pem +9 -0
  146. data/spec/fixtures/ec_key2.pem +6 -0
  147. data/spec/fixtures/hmacsha1.sig +1 -0
  148. data/spec/fixtures/hmacsha512.sig +1 -0
  149. data/spec/fixtures/key4.pem +0 -0
  150. data/spec/fixtures/key4_encrypted_des3.pem +0 -0
  151. data/spec/fixtures/missing_key_identifier_ca.cer +0 -0
  152. data/spec/fixtures/missing_key_identifier_ca.key +0 -0
  153. data/spec/fixtures/ocsptest.r509.local.pem +0 -0
  154. data/spec/fixtures/ocsptest.r509.local_ocsp_request.der +0 -0
  155. data/spec/fixtures/ocsptest2.r509.local.pem +0 -0
  156. data/spec/fixtures/second_ca.cer +0 -0
  157. data/spec/fixtures/second_ca.key +0 -0
  158. data/spec/fixtures/spkac.der +0 -0
  159. data/spec/fixtures/spkac.txt +0 -0
  160. data/spec/fixtures/spkac_dsa.txt +1 -1
  161. data/spec/fixtures/spkac_dsa_no_verify.txt +1 -0
  162. data/spec/fixtures/spkac_ec.txt +1 -0
  163. data/spec/fixtures/spkac_rsa_newlines.txt +13 -0
  164. data/spec/fixtures/stca.pem +0 -0
  165. data/spec/fixtures/stca_ocsp_request.der +0 -0
  166. data/spec/fixtures/stca_ocsp_response.der +0 -0
  167. data/spec/fixtures/test1.csr +0 -0
  168. data/spec/fixtures/test_ca.cer +0 -0
  169. data/spec/fixtures/test_ca.key +0 -0
  170. data/spec/fixtures/test_ca.p12 +0 -0
  171. data/spec/fixtures/test_ca_des3.key +0 -0
  172. data/spec/fixtures/test_ca_ec.cer +14 -0
  173. data/spec/fixtures/test_ca_ec.key +6 -0
  174. data/spec/fixtures/test_ca_ec_ee.cer +22 -0
  175. data/spec/fixtures/test_ca_ec_ee.key +6 -0
  176. data/spec/fixtures/test_ca_ocsp.cer +0 -0
  177. data/spec/fixtures/test_ca_ocsp.key +0 -0
  178. data/spec/fixtures/test_ca_ocsp.p12 +0 -0
  179. data/spec/fixtures/test_ca_ocsp_chain.txt +0 -0
  180. data/spec/fixtures/test_ca_ocsp_response.der +0 -0
  181. data/spec/fixtures/test_ca_subroot.cer +0 -0
  182. data/spec/fixtures/test_ca_subroot.key +0 -0
  183. data/spec/fixtures/test_ca_subroot_ocsp.cer +0 -0
  184. data/spec/fixtures/test_ca_subroot_ocsp.key +0 -0
  185. data/spec/fixtures/test_ca_subroot_ocsp_response.der +0 -0
  186. data/spec/fixtures/unknown_oid.csr +0 -0
  187. data/spec/message_digest_spec.rb +104 -84
  188. data/spec/ocsp_spec.rb +105 -105
  189. data/spec/oid_mapper_spec.rb +21 -21
  190. data/spec/private_key_spec.rb +275 -0
  191. data/spec/r509_spec.rb +35 -0
  192. data/spec/spec_helper.rb +15 -6
  193. data/spec/spki_spec.rb +221 -142
  194. data/spec/subject_spec.rb +232 -164
  195. data/spec/validity_spec.rb +91 -91
  196. metadata +79 -25
  197. data/doc/R509/Config/CaProfile.html +0 -651
  198. data/doc/R509/Crl/Administrator.html +0 -2073
  199. data/lib/r509/certificateauthority.rb +0 -290
  200. data/lib/r509/messagedigest.rb +0 -49
  201. data/lib/r509/oidmapper.rb +0 -32
  202. data/lib/r509/privatekey.rb +0 -185
  203. data/spec/privatekey_spec.rb +0 -198
@@ -6,7 +6,7 @@
6
6
  <title>
7
7
  Top Level Namespace
8
8
 
9
- &mdash; Documentation by YARD 0.8.2.1
9
+ &mdash; Documentation by YARD 0.8.5
10
10
 
11
11
  </title>
12
12
 
@@ -103,9 +103,9 @@
103
103
  </div>
104
104
 
105
105
  <div id="footer">
106
- Generated on Thu Nov 8 14:19:24 2012 by
106
+ Generated on Tue Apr 16 10:49:55 2013 by
107
107
  <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
108
- 0.8.2.1 (ruby-1.9.3).
108
+ 0.8.5 (ruby-1.9.3).
109
109
  </div>
110
110
 
111
111
  </body>
data/lib/r509.rb CHANGED
@@ -1,22 +1,38 @@
1
1
  # A module for building an easy to use CA. Includes CSR, Certificate, and CRL support.
2
2
  module R509
3
- require('r509/certificateauthority.rb')
4
- require('r509/csr.rb')
5
- require('r509/spki.rb')
6
- require('r509/cert.rb')
7
- require('r509/crl.rb')
8
- require('r509/oidmapper.rb')
9
- require('r509/ocsp.rb')
10
- require('r509/config.rb')
11
- require('r509/privatekey.rb')
12
- require('r509/messagedigest.rb')
13
- require('r509/subject.rb')
14
- require('r509/validity.rb')
3
+ require('r509/certificate_authority.rb')
4
+ require('r509/csr.rb')
5
+ require('r509/spki.rb')
6
+ require('r509/cert.rb')
7
+ require('r509/crl.rb')
8
+ require('r509/oid_mapper.rb')
9
+ require('r509/ocsp.rb')
10
+ require('r509/config.rb')
11
+ require('r509/private_key.rb')
12
+ require('r509/message_digest.rb')
13
+ require('r509/subject.rb')
14
+ require('r509/validity.rb')
15
+ require('r509/ec-hack.rb')
16
+ require('r509/asn1.rb')
17
+ require('r509/version.rb')
18
+
19
+ # print version information to console
20
+ def self.print_debug
21
+ puts "r509 v#{R509::VERSION}"
22
+ puts OpenSSL::OPENSSL_VERSION
23
+ puts "Ruby #{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}"
24
+ puts "Elliptic curve support: #{self.ec_supported?}"
25
+ end
26
+
27
+ def self.ec_supported?
28
+ (not defined?(OpenSSL::PKey::EC::UNSUPPORTED))
29
+ end
15
30
  end
16
31
 
17
32
  #add some global mappings we want available throughout r509
18
- R509::OidMapper.batch_register([
19
- { :oid => "2.5.4.15", :short_name => "businessCategory" },
20
- { :oid => "1.3.6.1.4.1.311.60.2.1.2", :short_name => "jurisdictionOfIncorporationStateOrProvinceName" },
21
- { :oid => "1.3.6.1.4.1.311.60.2.1.3", :short_name => "jurisdictionOfIncorporationCountryName" }
33
+ R509::OIDMapper.batch_register([
34
+ { :oid => "2.5.4.15", :short_name => "businessCategory" }, # extended validation related
35
+ { :oid => "1.3.6.1.4.1.311.60.2.1.2", :short_name => "jurisdictionOfIncorporationStateOrProvinceName" }, # extended validation related
36
+ { :oid => "1.3.6.1.4.1.311.60.2.1.3", :short_name => "jurisdictionOfIncorporationCountryName" }, # extended validation related
37
+ { :oid => "2.5.29.37.0", :short_name => "anyExtendedKeyUsage", :long_name => "Any Extended Key Usage" } # an EKU older OpenSSL frequently lacks
22
38
  ])
data/lib/r509/asn1.rb ADDED
@@ -0,0 +1,375 @@
1
+ require 'ipaddr'
2
+
3
+ module R509
4
+ # Module for holding various classes related to parsed ASN.1 objects
5
+ module ASN1
6
+ # parses the ASN.1 payload and gets the extension data out for further processing
7
+ # by the subclasses
8
+ def self.get_extension_payload(ext)
9
+ asn = OpenSSL::ASN1.decode ext
10
+ # Our extension object. Here's the structure:
11
+ # Extension ::= SEQUENCE {
12
+ # extnID OBJECT IDENTIFIER,
13
+ # critical BOOLEAN DEFAULT FALSE,
14
+ # extnValue OCTET STRING
15
+ # -- contains the DER encoding of an ASN.1 value
16
+ # -- corresponding to the extension type identified
17
+ # -- by extnID
18
+ # }
19
+ OpenSSL::ASN1.decode(asn.entries.last.value).value
20
+ end
21
+
22
+ # @param [Array] names An array of strings. Can be dNSName, iPAddress, URI, or rfc822Name.
23
+ # You can also supply a directoryName, but this must be an R509::Subject or array of arrays
24
+ # @return [R509::ASN1::GeneralNames]
25
+ def self.general_name_parser(names)
26
+ if names.nil?
27
+ return nil
28
+ end
29
+ general_names = R509::ASN1::GeneralNames.new
30
+ names.map do |domain|
31
+ if !(IPAddr.new(domain.strip) rescue nil).nil?
32
+ ip = IPAddr.new(domain.strip)
33
+ general_names.create_item(:tag => 7, :value => ip.to_s)
34
+ else
35
+ case domain
36
+ when R509::Subject, Array
37
+ subject = R509::Subject.new(domain)
38
+ general_names.create_item(:tag => 4, :value => subject)
39
+ when /:\/\// #URI
40
+ general_names.create_item(:tag => 6, :value => domain.strip)
41
+ when /@/ #rfc822Name
42
+ general_names.create_item(:tag => 1, :value => domain.strip)
43
+ else #dNSName
44
+ general_names.create_item(:tag => 2, :value => domain.strip)
45
+ end
46
+ end
47
+ end
48
+ general_names
49
+ end
50
+
51
+ # This class parses ASN.1 GeneralName objects. At the moment it supports
52
+ # rfc822Name, dNSName, directoryName, uniformResourceIdentifier, and iPAddress
53
+ # GeneralName ::= CHOICE {
54
+ # otherName [0] OtherName,
55
+ # rfc822Name [1] IA5String,
56
+ # dNSName [2] IA5String,
57
+ # x400Address [3] ORAddress,
58
+ # directoryName [4] Name,
59
+ # ediPartyName [5] EDIPartyName,
60
+ # uniformResourceIdentifier [6] IA5String,
61
+ # iPAddress [7] OCTET STRING,
62
+ # registeredID [8] OBJECT IDENTIFIER }
63
+ class GeneralName
64
+ # The type, represented as a symbolized version of the GeneralName (e.g. :dNSName)
65
+ attr_reader :type
66
+ # The prefix OpenSSL needs for this type when encoding it into an extension.
67
+ attr_reader :serial_prefix
68
+ # Value of the GeneralName
69
+ attr_reader :value
70
+ # Integer tag type. See GeneralName description at the top of this class
71
+ attr_reader :tag
72
+
73
+ # @param [OpenSSL::ASN1::ASN1Data,Hash] asn ASN.1 input data. Can also pass a hash with :tag and :value keys
74
+ def initialize(asn)
75
+ if asn.kind_of?(Hash) and asn.has_key?(:tag) and asn.has_key?(:value)
76
+ # this is added via create_item
77
+ @tag = asn[:tag]
78
+ @type = R509::ASN1::GeneralName.map_tag_to_type(@tag)
79
+ @serial_prefix = R509::ASN1::GeneralName.map_tag_to_serial_prefix(@tag)
80
+ @value = asn[:value]
81
+ else
82
+ @tag = asn.tag
83
+ @type = R509::ASN1::GeneralName.map_tag_to_type(@tag)
84
+ @serial_prefix = R509::ASN1::GeneralName.map_tag_to_serial_prefix(@tag)
85
+ value = asn.value
86
+ case @tag
87
+ when 1 then @value = value
88
+ when 2 then @value = value
89
+ when 4 then @value = R509::Subject.new(value.first.to_der)
90
+ when 6 then @value = value
91
+ when 7
92
+ if value.size == 4 or value.size == 16
93
+ ip = IPAddr.new_ntoh(value)
94
+ @value = ip.to_s
95
+ elsif value.size == 8 #IPv4 with netmask
96
+ ip = IPAddr.new_ntoh(value[0,4])
97
+ netmask = IPAddr.new_ntoh(value[4,4])
98
+ @value = ip.to_s + "/" + netmask.to_s
99
+ elsif value.size == 32 #IPv6 with netmask
100
+ ip = IPAddr.new_ntoh(value[0,16])
101
+ netmask = IPAddr.new_ntoh(value[16,16])
102
+ @value = ip.to_s + "/" + netmask.to_s
103
+ end
104
+ end
105
+ end
106
+ end
107
+
108
+ # Maps a GeneralName type to the integer tag representation
109
+ # @param [String,Symbol] type of GeneralName
110
+ # @return [Integer] tag for the type
111
+ def self.map_type_to_tag(type)
112
+ # otherName [0] OtherName,
113
+ # rfc822Name [1] IA5String,
114
+ # dNSName [2] IA5String,
115
+ # x400Address [3] ORAddress,
116
+ # directoryName [4] Name,
117
+ # ediPartyName [5] EDIPartyName,
118
+ # uniformResourceIdentifier [6] IA5String,
119
+ # iPAddress [7] OCTET STRING,
120
+ # registeredID [8] OBJECT IDENTIFIER }
121
+ case type
122
+ when "otherName", :otherName then 0
123
+ when "rfc822Name", :rfc822Name, "email" then 1
124
+ when "dNSName", :dNSName, "DNS" then 2
125
+ when "x400Address", :x400Address then 3
126
+ when "directoryName", :directoryName, "dirName" then 4
127
+ when "ediPartyName", :ediPartyName then 5
128
+ when "uniformResourceIdentifier", :uniformResourceIdentifier, "URI" then 6
129
+ when "iPAddress", :iPAddress, "IP" then 7
130
+ when "registeredID", :registeredID then 8
131
+ end
132
+ end
133
+
134
+ # @param [Integer] tag
135
+ # @return [String] serial prefix
136
+ def self.map_tag_to_serial_prefix(tag)
137
+ case tag
138
+ when 1 then "email"
139
+ when 2 then "DNS"
140
+ when 4 then "dirName"
141
+ when 6 then "URI"
142
+ when 7 then "IP"
143
+ else
144
+ raise R509Error, "Unimplemented GeneralName tag: #{tag}. At this time R509 does not support GeneralName types other than rfc822Name, dNSName, uniformResourceIdentifier, iPAddress, and directoryName"
145
+ end
146
+ end
147
+
148
+ # @param [Integer] tag
149
+ # @return [Symbol] symbol type
150
+ def self.map_tag_to_type(tag)
151
+ case tag
152
+ when 0 then :otherName
153
+ when 1 then :rfc822Name
154
+ when 2 then :dNSName
155
+ when 3 then :x400Address
156
+ when 4 then :directoryName
157
+ when 5 then :ediPartyName
158
+ when 6 then :uniformResourceIdentifier
159
+ when 7 then :iPAddress
160
+ when 8 then :registeredID
161
+ else
162
+ raise R509Error, "Invalid tag #{tag}"
163
+ end
164
+ end
165
+
166
+ # @private
167
+ # required for #uniq comparisons
168
+ # @return [Boolean] equality between objects
169
+ def ==(other)
170
+ (other.class == self.class and self.type == other.type && self.value == other.value)
171
+ end
172
+ alias_method :eql?, :==
173
+
174
+ # @private
175
+ # required for #uniq comparisons
176
+ def hash
177
+ "#{self.type}#{self.tag}#{self.value}".hash
178
+ end
179
+
180
+ # Used to serialize GeneralName objects when issuing new certificates inside R509::CertificateAuthority::Signer
181
+ # @return [Hash] conf section and name serialized for OpenSSL extension creation
182
+ def serialize_name
183
+ if self.type == :directoryName
184
+ conf_name = OpenSSL::Random.random_bytes(16).unpack("H*")[0]
185
+ conf = []
186
+ conf << "[#{conf_name}]"
187
+ @value.to_a.each do |el|
188
+ conf << "#{el[0]}=#{el[1]}"
189
+ end
190
+ conf = conf.join("\n")
191
+ extension_string = self.serial_prefix + ":" + conf_name
192
+ else
193
+ conf = nil
194
+ extension_string = self.serial_prefix + ":" + self.value
195
+ end
196
+ {
197
+ :conf => conf,
198
+ :extension_string => extension_string
199
+ }
200
+ end
201
+ end
202
+
203
+ # object to hold parsed sequences of generalnames
204
+ # these structures are used in SubjectAlternativeName, AuthorityInfoAccess, CRLDistributionPoints, etc
205
+ class GeneralNames
206
+ def initialize
207
+ @types = {
208
+ :otherName => [], # unimplemented
209
+ :rfc822Name => [],
210
+ :dNSName => [],
211
+ :x400Address => [], # unimplemented
212
+ :directoryName => [],
213
+ :ediPartyName => [], # unimplemented
214
+ :uniformResourceIdentifier => [],
215
+ :iPAddress => [],
216
+ :registeredID => [] # unimplemented
217
+ }
218
+ @ordered_names = []
219
+ end
220
+
221
+ # @private
222
+ # @param [OpenSSL::ASN1::ASN1Data] asn Takes ASN.1 data in for parsing GeneralName structures
223
+ def add_item(asn)
224
+ # map general names into our hash of arrays
225
+ if asn.kind_of?(R509::ASN1::GeneralName)
226
+ @ordered_names << asn
227
+ @types[asn.type] << asn.value
228
+ else
229
+ gn = R509::ASN1::GeneralName.new(asn)
230
+ @ordered_names << gn
231
+ @types[gn.type] << gn.value
232
+ end
233
+ end
234
+
235
+ # @private
236
+ # @param [Hash] hash A hash with (:tag or :type) and :value keys. Allows you to build GeneralName objects and add
237
+ # them to the GeneralNames object. Unless you know what you're doing you should really stay away from this.
238
+ def create_item(hash)
239
+ if not hash.respond_to?(:has_key?) or (not hash.has_key?(:tag) and not hash.has_key?(:type)) or not hash.has_key?(:value)
240
+ raise ArgumentError, "Must be a hash with (:tag or :type) and :value nodes"
241
+ end
242
+ if hash[:type]
243
+ hash[:tag] = R509::ASN1::GeneralName.map_type_to_tag(hash[:type])
244
+ end
245
+ gn = R509::ASN1::GeneralName.new(:tag => hash[:tag], :value => hash[:value])
246
+ add_item(gn)
247
+ end
248
+
249
+ # @return [Array] array of GeneralName objects
250
+ # order found in the extension
251
+ def names
252
+ @ordered_names
253
+ end
254
+
255
+ # @return [Array] Array of rfc822name strings
256
+ def rfc_822_names
257
+ @types[:rfc822Name]
258
+ end
259
+
260
+ # @return [Array] Array of dnsName strings
261
+ def dns_names
262
+ @types[:dNSName]
263
+ end
264
+
265
+ # @return [Array] Array of uri strings
266
+ def uniform_resource_identifiers
267
+ @types[:uniformResourceIdentifier]
268
+ end
269
+ alias_method :uris, :uniform_resource_identifiers
270
+
271
+ # @return [Array] Array of IP address strings
272
+ def ip_addresses
273
+ @types[:iPAddress]
274
+ end
275
+
276
+ # @return [Array] Array of directoryNames (R509::Subject objects)
277
+ def directory_names
278
+ @types[:directoryName]
279
+ end
280
+
281
+ # @return [Array] string of serialized names for OpenSSL extension creation
282
+ def serialize_names
283
+ confs = []
284
+ extension_strings = []
285
+ @ordered_names.each { |item|
286
+ data = item.serialize_name
287
+ confs << data[:conf]
288
+ extension_strings << data[:extension_string]
289
+ }
290
+ { :conf => confs.join("\n"), :extension_string => extension_strings.join(",") }
291
+ end
292
+ end
293
+
294
+ # PolicyInformation ::= SEQUENCE {
295
+ # policyIdentifier CertPolicyId,
296
+ # policyQualifiers SEQUENCE SIZE (1..MAX) OF
297
+ # PolicyQualifierInfo OPTIONAL }
298
+ class PolicyInformation
299
+ attr_reader :policy_identifier, :policy_qualifiers
300
+ def initialize(data)
301
+ # store the policy identifier OID
302
+ @policy_identifier = data.entries[0].value
303
+ # iterate the policy qualifiers if any exist
304
+ if not data.entries[1].nil?
305
+ @policy_qualifiers = PolicyQualifiers.new
306
+ data.entries[1].each do |pq|
307
+ @policy_qualifiers.parse(pq)
308
+ end
309
+ end
310
+ end
311
+ end
312
+
313
+ # PolicyQualifierInfo ::= SEQUENCE {
314
+ # policyQualifierId PolicyQualifierId,
315
+ # qualifier ANY DEFINED BY policyQualifierId }
316
+ class PolicyQualifiers
317
+ attr_reader :cps_uris, :user_notices
318
+ def initialize
319
+ @cps_uris = []
320
+ @user_notices = []
321
+ end
322
+
323
+ # parse each PolicyQualifier and store the results into the object array
324
+ def parse(data)
325
+ oid = data.entries[0].value
326
+ case
327
+ when oid == 'id-qt-cps'
328
+ @cps_uris << data.entries[1].value
329
+ when oid == 'id-qt-unotice'
330
+ @user_notices << UserNotice.new(data.entries[1])
331
+ end
332
+ end
333
+ end
334
+
335
+ # UserNotice ::= SEQUENCE {
336
+ # noticeRef NoticeReference OPTIONAL,
337
+ # explicitText DisplayText OPTIONAL }
338
+ class UserNotice
339
+ attr_reader :notice_reference, :explicit_text
340
+ def initialize(data)
341
+ data.each do |qualifier|
342
+ #if we find another sequence, that's a noticeReference, otherwise it's explicitText
343
+ if qualifier.kind_of?(OpenSSL::ASN1::Sequence)
344
+ @notice_reference = NoticeReference.new(qualifier)
345
+ else
346
+ @explicit_text = qualifier.value
347
+ end
348
+
349
+ end if data.respond_to?(:each)
350
+ end
351
+ end
352
+
353
+ # NoticeReference ::= SEQUENCE {
354
+ # organization DisplayText,
355
+ # noticeNumbers SEQUENCE OF INTEGER }
356
+ class NoticeReference
357
+ attr_reader :organization, :notice_numbers
358
+ def initialize(data)
359
+ data.each do |notice_reference|
360
+ # if it's displaytext then it's the organization
361
+ # if it's YET ANOTHER ASN1::Sequence, then it's noticeNumbers
362
+ if notice_reference.kind_of?(OpenSSL::ASN1::Sequence)
363
+ @notice_numbers = []
364
+ notice_reference.each do |ints|
365
+ @notice_numbers << ints.value
366
+ end
367
+ else
368
+ @organization = notice_reference.value
369
+ end
370
+ end
371
+ end
372
+ end
373
+
374
+ end
375
+ end