r509 0.8.1 → 0.9

Sign up to get free protection for your applications and to get access to all the features.
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
data/lib/r509/validity.rb CHANGED
@@ -2,91 +2,93 @@ require 'openssl'
2
2
 
3
3
  #Module for holding classes for writing and reading certificate validity information (used for serving OCSP responses)
4
4
  module R509::Validity
5
- #mapping from OpenSSL
6
- VALID = OpenSSL::OCSP::V_CERTSTATUS_GOOD
7
- REVOKED = OpenSSL::OCSP::V_CERTSTATUS_REVOKED
8
- UNKNOWN = OpenSSL::OCSP::V_CERTSTATUS_UNKNOWN
5
+ #mapping from OpenSSL
6
+ VALID = OpenSSL::OCSP::V_CERTSTATUS_GOOD
7
+ #mapping from OpenSSL
8
+ REVOKED = OpenSSL::OCSP::V_CERTSTATUS_REVOKED
9
+ #mapping from OpenSSL
10
+ UNKNOWN = OpenSSL::OCSP::V_CERTSTATUS_UNKNOWN
9
11
 
10
- #data about the status of a certificate
11
- class Status
12
- attr_reader :status, :revocation_time, :revocation_reason
12
+ #data about the status of a certificate
13
+ class Status
14
+ attr_reader :status, :revocation_time, :revocation_reason
13
15
 
14
- def initialize(options={})
15
- @status = options[:status]
16
- @revocation_time = options[:revocation_time] || nil
17
- @revocation_reason = options[:revocation_reason] || 0
16
+ def initialize(options={})
17
+ @status = options[:status]
18
+ @revocation_time = options[:revocation_time] || nil
19
+ @revocation_reason = options[:revocation_reason] || 0
18
20
 
19
- if (@status == R509::Validity::REVOKED and @revocation_time.nil?)
20
- @revocation_time = Time.now.to_i
21
- end
22
- end
21
+ if (@status == R509::Validity::REVOKED and @revocation_time.nil?)
22
+ @revocation_time = Time.now.to_i
23
+ end
24
+ end
23
25
 
24
- # @return [OpenSSL::OCSP::STATUS] OpenSSL status constants when passing R509 constants
25
- def ocsp_status
26
- case @status
27
- when R509::Validity::VALID
28
- OpenSSL::OCSP::V_CERTSTATUS_GOOD
29
- when R509::Validity::REVOKED
30
- OpenSSL::OCSP::V_CERTSTATUS_REVOKED
31
- when R509::Validity::UNKNOWN
32
- OpenSSL::OCSP::V_CERTSTATUS_UNKNOWN
33
- else
34
- OpenSSL::OCSP::V_CERTSTATUS_UNKNOWN
35
- end
36
- end
26
+ # @return [OpenSSL::OCSP::STATUS] OpenSSL status constants when passing R509 constants
27
+ def ocsp_status
28
+ case @status
29
+ when R509::Validity::VALID
30
+ OpenSSL::OCSP::V_CERTSTATUS_GOOD
31
+ when R509::Validity::REVOKED
32
+ OpenSSL::OCSP::V_CERTSTATUS_REVOKED
33
+ when R509::Validity::UNKNOWN
34
+ OpenSSL::OCSP::V_CERTSTATUS_UNKNOWN
35
+ else
36
+ OpenSSL::OCSP::V_CERTSTATUS_UNKNOWN
37
+ end
37
38
  end
39
+ end
38
40
 
39
- #abstract base class for a Writer
40
- class Writer
41
- def issue(issuer, serial)
42
- raise NotImplementedError, "You must call #issue on a subclass of Writer"
43
- end
41
+ #abstract base class for a Writer
42
+ class Writer
43
+ def issue(issuer, serial)
44
+ raise NotImplementedError, "You must call #issue on a subclass of Writer"
45
+ end
44
46
 
45
- def revoke(issuer, serial, reason)
46
- raise NotImplementedError, "You must call #revoke on a subclass of Writer"
47
- end
47
+ def revoke(issuer, serial, reason)
48
+ raise NotImplementedError, "You must call #revoke on a subclass of Writer"
49
+ end
48
50
 
49
- # is_available? is meant to be implemented to check if the backend store you choose to implement is currently working.
50
- # see r509-ocsp-responder and r509-validity-redis for an example of use
51
- def is_available?
52
- raise NotImplementedError, "You must call #is_available? on a subclass of Writer"
53
- end
51
+ # is_available? is meant to be implemented to check if the backend store you choose to implement is currently working.
52
+ # see r509-ocsp-responder and r509-validity-redis for an example of use
53
+ def is_available?
54
+ raise NotImplementedError, "You must call #is_available? on a subclass of Writer"
54
55
  end
56
+ end
55
57
 
56
- #abstract base class for a Checker
57
- class Checker
58
- def check(issuer, serial)
59
- raise NotImplementedError, "You must call #check on a subclass of Checker"
60
- end
58
+ #abstract base class for a Checker
59
+ class Checker
60
+ def check(issuer, serial)
61
+ raise NotImplementedError, "You must call #check on a subclass of Checker"
62
+ end
61
63
 
62
- # is_available? is meant to be implemented to check if the backend store you choose to implement is currently working.
63
- # see r509-ocsp-responder and r509-validity-redis for an example of use
64
- def is_available?
65
- raise NotImplementedError, "You must call #is_available? on a subclass of Checker"
66
- end
64
+ # is_available? is meant to be implemented to check if the backend store you choose to implement is currently working.
65
+ # see r509-ocsp-responder and r509-validity-redis for an example of use
66
+ def is_available?
67
+ raise NotImplementedError, "You must call #is_available? on a subclass of Checker"
67
68
  end
69
+ end
68
70
 
69
- #default implementaton of the Checker class. Used for tests. DO NOT USE OTHERWISE
70
- class DefaultChecker < R509::Validity::Checker
71
- def check(issuer, serial)
72
- R509::Validity::Status.new(:status => R509::Validity::VALID)
73
- end
71
+ #default implementaton of the Checker class. Used for tests. DO NOT USE OTHERWISE
72
+ class DefaultChecker < R509::Validity::Checker
73
+ def check(issuer, serial)
74
+ R509::Validity::Status.new(:status => R509::Validity::VALID)
75
+ end
74
76
 
75
- def is_available?
76
- true
77
- end
77
+ def is_available?
78
+ true
78
79
  end
80
+ end
79
81
 
80
- #default implementaton of the Writer class. Does nothing (obviously)
81
- class DefaultWriter < R509::Validity::Writer
82
- def issue(issuer, serial)
83
- end
82
+ #default implementaton of the Writer class. Does nothing (obviously)
83
+ class DefaultWriter < R509::Validity::Writer
84
+ def issue(issuer, serial)
85
+ end
84
86
 
85
- def revoke(issuer, serial, reason)
86
- end
87
+ def revoke(issuer, serial, reason)
88
+ end
87
89
 
88
- def is_available?
89
- true
90
- end
90
+ def is_available?
91
+ true
91
92
  end
93
+ end
92
94
  end
data/lib/r509/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  module R509
2
- #The version of the r509 gem
3
- VERSION="0.8.1"
2
+ #The version of the r509 gem
3
+ VERSION="0.9"
4
4
  end
data/r509.yaml CHANGED
@@ -1,73 +1,96 @@
1
1
  certificate_authorities: {
2
- test_ca: {
3
- ca_cert: {
4
- cert: 'spec/fixtures/test_ca.cer',
5
- key: 'spec/fixtures/test_ca.key'
6
- },
7
- ocsp_cert: {
8
- :pkcs12: 'spec/fixtures/test_ca_ocsp.p12',
9
- :password: 'r509'
10
- },
11
- ocsp_location: 'URI:http://ocsp.domain.com',
12
- ocsp_chain: 'spec/fixtures/test_ca_ocsp_chain.txt',
13
- ocsp_start_skew_seconds: 3600,
14
- ocsp_validity_hours: 168,
15
- cdp_location: 'URI:http://crl.domain.com/test_ca.crl',
16
- crl_list: 'spec/fixtures/test_ca_crl_list.txt',
17
- crl_number: 'spec/fixtures/test_ca_crl_number.txt',
18
- crl_validity_hours: 168, #7 days
19
- message_digest: 'SHA1', #SHA1, SHA256, SHA512 supported. MD5 too, but you really shouldn't use that unless you have a good reason
20
- profiles: {
21
- server: {
22
- basic_constraints: "CA:FALSE",
23
- key_usage: [digitalSignature,keyEncipherment],
24
- extended_key_usage: [serverAuth],
25
- certificate_policies: [ [ "policyIdentifier=2.16.840.1.9999999999.1.2.3.4.1", "CPS.1=http://example.com/cps"] ],
26
- subject_item_policy: {
27
- CN: "required",
28
- O: "required",
29
- OU: "optional",
30
- ST: "required",
31
- C: "required",
32
- L: "required"
33
- }
34
- },
35
- client: {
36
- basic_constraints: "CA:FALSE",
37
- key_usage: [digitalSignature,keyEncipherment],
38
- extended_key_usage: [clientAuth],
39
- certificate_policies: [ [ "policyIdentifier=2.16.840.1.9999999999.1.2.3.4.2", "CPS.1=http://example.com/cps"] ]
40
- },
41
- email: {
42
- basic_constraints: "CA:FALSE",
43
- key_usage: [digitalSignature,keyEncipherment],
44
- extended_key_usage: [emailProtection],
45
- certificate_policies: [ [ "policyIdentifier=2.16.840.1.9999999999.1.2.3.4.3", "CPS.1=http://example.com/cps"] ]
46
- },
47
- clientserver: {
48
- basic_constraints: "CA:FALSE",
49
- key_usage: [digitalSignature,keyEncipherment],
50
- extended_key_usage: [serverAuth,clientAuth],
51
- certificate_policies: [ [ "policyIdentifier=2.16.840.1.9999999999.1.2.3.4.4", "CPS.1=http://example.com/cps"] ]
52
- },
53
- codesigning: {
54
- basic_constraints: "CA:FALSE",
55
- key_usage: [digitalSignature],
56
- extended_key_usage: [codeSigning],
57
- certificate_policies: [ [ "policyIdentifier=2.16.840.1.9999999999.1.2.3.4.5", "CPS.1=http://example.com/cps"] ]
58
- },
59
- timestamping: {
60
- basic_constraints: "CA:FALSE",
61
- key_usage: [digitalSignature],
62
- extended_key_usage: [timeStamping],
63
- certificate_policies: [ [ "policyIdentifier=2.16.840.1.9999999999.1.2.3.4.6", "CPS.1=http://example.com/cps"] ]
64
- },
65
- subroot: {
66
- basic_constraints: "CA:TRUE,pathlen:0",
67
- key_usage: [keyCertSign,cRLSign],
68
- extended_key_usage: [],
69
- certificate_policies: [ ]
70
- }
2
+ test_ca: {
3
+ ca_cert: {
4
+ cert: 'spec/fixtures/test_ca.cer',
5
+ key: 'spec/fixtures/test_ca.key'
6
+ },
7
+ ocsp_cert: {
8
+ pkcs12: 'spec/fixtures/test_ca_ocsp.p12',
9
+ password: 'r509'
10
+ },
11
+ ocsp_location: ['http://ocsp.domain.com'],
12
+ ca_issuers_location: ['http://domain.com/ca.html'],
13
+ ocsp_chain: 'spec/fixtures/test_ca_ocsp_chain.txt',
14
+ ocsp_start_skew_seconds: 3600,
15
+ ocsp_validity_hours: 168,
16
+ cdp_location: ['http://crl.domain.com/test_ca.crl'],
17
+ crl_list: 'spec/fixtures/test_ca_crl_list.txt',
18
+ crl_number: 'spec/fixtures/test_ca_crl_number.txt',
19
+ crl_validity_hours: 168, #7 days
20
+ message_digest: 'SHA1', #SHA1, SHA256, SHA512 supported. MD5 too, but you really shouldn't use that unless you have a good reason
21
+ profiles: {
22
+ server: {
23
+ basic_constraints: {"ca" : false},
24
+ key_usage: [digitalSignature,keyEncipherment],
25
+ extended_key_usage: [serverAuth],
26
+ subject_item_policy: {
27
+ CN: "required",
28
+ O: "required",
29
+ OU: "optional",
30
+ ST: "required",
31
+ C: "required",
32
+ L: "required"
71
33
  }
34
+ },
35
+ client: {
36
+ basic_constraints: {"ca" : false},
37
+ key_usage: [digitalSignature,keyEncipherment],
38
+ extended_key_usage: [clientAuth],
39
+ },
40
+ email: {
41
+ basic_constraints: {"ca" : false},
42
+ key_usage: [digitalSignature,keyEncipherment],
43
+ extended_key_usage: [emailProtection],
44
+ },
45
+ clientserver: {
46
+ basic_constraints: {"ca" : false},
47
+ key_usage: [digitalSignature,keyEncipherment],
48
+ extended_key_usage: [serverAuth,clientAuth],
49
+ },
50
+ codesigning: {
51
+ basic_constraints: {"ca" : false},
52
+ key_usage: [digitalSignature],
53
+ extended_key_usage: [codeSigning],
54
+ },
55
+ timestamping: {
56
+ basic_constraints: {"ca" : false},
57
+ key_usage: [digitalSignature],
58
+ extended_key_usage: [timeStamping],
59
+ },
60
+ subroot: {
61
+ basic_constraints: {"ca" : true, "path_length" : 0},
62
+ key_usage: [keyCertSign,cRLSign],
63
+ extended_key_usage: [],
64
+ certificate_policies: [
65
+ { policy_identifier: "2.16.840.1.99999.21.234",
66
+ cps_uris: ["http://example.com/cps","http://haha.com"],
67
+ user_notices: [ { explicit_text: "this is a great thing", organization: "my org", notice_numbers: "1,2,3" } ]
68
+ },
69
+ { policy_identifier: "2.16.840.1.99999.21.235",
70
+ cps_uris: ["http://example.com/cps2"],
71
+ user_notices: [ { explicit_text: "this is a bad thing", organization: "another org", notice_numbers: "3,2,1" },{ explicit_text: "another user notice"} ]
72
+ }
73
+ ],
74
+ inhibit_any_policy: 0,
75
+ policy_constraints: { require_explicit_policy: 0, inhibit_policy_mapping: 0},
76
+ name_constraints: {
77
+ permitted: [
78
+ {type: "IP", value: "192.168.0.0/255.255.0.0"},
79
+ {type: "dirName", value: [['CN','myCN'],['O','Org']]}
80
+ ],
81
+ excluded: [
82
+ {type: "email", value: "domain.com"},
83
+ {type: "URI", value: ".net"},
84
+ {type: "DNS", value: "test.us"}
85
+ ]
86
+ }
87
+ },
88
+ ocsp_delegate: {
89
+ basic_constraints: {"ca" : false},
90
+ key_usage: [digitalSignature],
91
+ extended_key_usage: [OCSPSigning],
92
+ ocsp_no_check: true
93
+ }
72
94
  }
95
+ }
73
96
  }
data/spec/asn1_spec.rb ADDED
@@ -0,0 +1,402 @@
1
+ require 'spec_helper'
2
+ require 'r509/asn1'
3
+
4
+ describe R509::ASN1 do
5
+ it "does not error with valid extension on get_extension_payload" do
6
+ #SAN extension
7
+ der = "0L\u0006\u0003U\u001D\u0011\u0001\u0001\xFF\u0004B0@\x82\u000Ewww.test.local\x87\u0004\n\u0001\u0002\u0003\x86\u0015http://www.test.local\x81\u0011myemail@email.com"
8
+ ext = OpenSSL::X509::Extension.new(der)
9
+ payload = R509::ASN1.get_extension_payload(ext)
10
+ payload.should_not be_nil
11
+ end
12
+
13
+ context "general_name_parser" do
14
+ it "returns nil if passed nil" do
15
+ general_names = R509::ASN1.general_name_parser(nil)
16
+ general_names.should be_nil
17
+ end
18
+ it "correctly parses dns names" do
19
+ general_names = R509::ASN1.general_name_parser(['domain2.com','domain3.com'])
20
+ general_names.dns_names.should == ["domain2.com", "domain3.com"]
21
+ end
22
+
23
+ it "adds SAN IPv4 names" do
24
+ general_names = R509::ASN1.general_name_parser(['1.2.3.4','2.3.4.5'])
25
+ general_names.ip_addresses.should == ["1.2.3.4", "2.3.4.5"]
26
+ end
27
+
28
+ it "adds SAN IPv6 names" do
29
+ general_names = R509::ASN1.general_name_parser(['FE80:0:0:0:0:0:0:1','fe80::2',])
30
+ general_names.ip_addresses.should == ["fe80::1", "fe80::2"]
31
+ end
32
+
33
+ it "adds SAN URI names" do
34
+ general_names = R509::ASN1.general_name_parser(['http://myuri.com','ftp://whyftp'])
35
+ general_names.uris.should == ['http://myuri.com','ftp://whyftp']
36
+ end
37
+
38
+ it "adds SAN rfc822 names" do
39
+ general_names = R509::ASN1.general_name_parser(['email@domain.com','some@other.com'])
40
+ general_names.rfc_822_names.should == ['email@domain.com','some@other.com']
41
+ end
42
+
43
+ it "adds directoryNames via R509::Subject objects" do
44
+ s = R509::Subject.new([['CN','what-what']])
45
+ s2 = R509::Subject.new([['C','US'],['L','locality']])
46
+ general_names = R509::ASN1.general_name_parser([s,s2])
47
+ general_names.directory_names.size.should == 2
48
+ general_names.directory_names[0].CN.should == 'what-what'
49
+ general_names.directory_names[0].C.should be_nil
50
+ general_names.directory_names[1].C.should == 'US'
51
+ general_names.directory_names[1].L.should == 'locality'
52
+ end
53
+
54
+ it "adds directoryNames via arrays" do
55
+ s = [['CN','what-what']]
56
+ s2 = [['C','US'],['L','locality']]
57
+ general_names = R509::ASN1.general_name_parser([s,s2])
58
+ general_names.directory_names.size.should == 2
59
+ general_names.directory_names[0].CN.should == 'what-what'
60
+ general_names.directory_names[0].C.should be_nil
61
+ general_names.directory_names[1].C.should == 'US'
62
+ general_names.directory_names[1].L.should == 'locality'
63
+ end
64
+
65
+ it "adds a mix of SAN name types" do
66
+ general_names = R509::ASN1.general_name_parser(['1.2.3.4','http://langui.sh','email@address.local','domain.internal','2.3.4.5'])
67
+ general_names.ip_addresses.should == ['1.2.3.4','2.3.4.5']
68
+ general_names.dns_names.should == ['domain.internal']
69
+ general_names.uris.should == ['http://langui.sh']
70
+ general_names.rfc_822_names.should == ['email@address.local']
71
+ end
72
+
73
+ it "handles empty array" do
74
+ general_names = R509::ASN1.general_name_parser([])
75
+ general_names.names.size.should == 0
76
+ end
77
+
78
+ end
79
+ end
80
+
81
+ describe R509::ASN1::GeneralName do
82
+ context "parses types to tags within ::map_type_to_tag" do
83
+ it "handles otherName" do
84
+ R509::ASN1::GeneralName.map_type_to_tag(:otherName).should == 0
85
+ R509::ASN1::GeneralName.map_type_to_tag("otherName").should == 0
86
+ end
87
+ it "handles rfc822Name" do
88
+ R509::ASN1::GeneralName.map_type_to_tag(:rfc822Name).should == 1
89
+ R509::ASN1::GeneralName.map_type_to_tag("rfc822Name").should == 1
90
+ R509::ASN1::GeneralName.map_type_to_tag("email").should == 1
91
+ end
92
+ it "handles dNSName" do
93
+ R509::ASN1::GeneralName.map_type_to_tag(:dNSName).should == 2
94
+ R509::ASN1::GeneralName.map_type_to_tag("dNSName").should == 2
95
+ R509::ASN1::GeneralName.map_type_to_tag("DNS").should == 2
96
+ end
97
+ it "handles x400Address" do
98
+ R509::ASN1::GeneralName.map_type_to_tag(:x400Address).should == 3
99
+ R509::ASN1::GeneralName.map_type_to_tag("x400Address").should == 3
100
+ end
101
+ it "handles directoryName" do
102
+ R509::ASN1::GeneralName.map_type_to_tag(:directoryName).should == 4
103
+ R509::ASN1::GeneralName.map_type_to_tag("directoryName").should == 4
104
+ R509::ASN1::GeneralName.map_type_to_tag("dirName").should == 4
105
+ end
106
+ it "handles ediPartyName" do
107
+ R509::ASN1::GeneralName.map_type_to_tag(:ediPartyName).should == 5
108
+ R509::ASN1::GeneralName.map_type_to_tag("ediPartyName").should == 5
109
+ end
110
+ it "handles uniformResourceIdentifier" do
111
+ R509::ASN1::GeneralName.map_type_to_tag(:uniformResourceIdentifier).should == 6
112
+ R509::ASN1::GeneralName.map_type_to_tag("uniformResourceIdentifier").should == 6
113
+ R509::ASN1::GeneralName.map_type_to_tag("URI").should == 6
114
+ end
115
+ it "handles iPAddress" do
116
+ R509::ASN1::GeneralName.map_type_to_tag(:iPAddress).should == 7
117
+ R509::ASN1::GeneralName.map_type_to_tag("iPAddress").should == 7
118
+ R509::ASN1::GeneralName.map_type_to_tag("IP").should == 7
119
+ end
120
+ it "handles registeredID" do
121
+ R509::ASN1::GeneralName.map_type_to_tag(:registeredID).should == 8
122
+ R509::ASN1::GeneralName.map_type_to_tag("registeredID").should == 8
123
+ end
124
+ end
125
+ context "::map_tag_to_type" do
126
+ it "handles otherName" do
127
+ R509::ASN1::GeneralName.map_tag_to_type(0).should == :otherName
128
+ end
129
+ it "handles rfc822Name" do
130
+ R509::ASN1::GeneralName.map_tag_to_type(1).should == :rfc822Name
131
+ end
132
+ it "handles dNSName" do
133
+ R509::ASN1::GeneralName.map_tag_to_type(2).should == :dNSName
134
+ end
135
+ it "handles x400Address" do
136
+ R509::ASN1::GeneralName.map_tag_to_type(3).should == :x400Address
137
+ end
138
+ it "handles directoryName" do
139
+ R509::ASN1::GeneralName.map_tag_to_type(4).should == :directoryName
140
+ end
141
+ it "handles ediPartyName" do
142
+ R509::ASN1::GeneralName.map_tag_to_type(5).should == :ediPartyName
143
+ end
144
+ it "handles uniformResourceIdentifier" do
145
+ R509::ASN1::GeneralName.map_tag_to_type(6).should == :uniformResourceIdentifier
146
+ end
147
+ it "handles iPAddress" do
148
+ R509::ASN1::GeneralName.map_tag_to_type(7).should == :iPAddress
149
+ end
150
+ it "handles registeredID" do
151
+ R509::ASN1::GeneralName.map_tag_to_type(8).should == :registeredID
152
+ end
153
+ it "raises error with invalid tag" do
154
+ expect { R509::ASN1::GeneralName.map_tag_to_type(28) }.to raise_error(R509::R509Error,"Invalid tag 28")
155
+ end
156
+
157
+ end
158
+ context "::map_tag_to_serial_prefix" do
159
+ it "handles otherName" do
160
+ expect { R509::ASN1::GeneralName.map_tag_to_serial_prefix(0) }.to raise_error(R509::R509Error)
161
+ end
162
+ it "handles rfc822Name" do
163
+ R509::ASN1::GeneralName.map_tag_to_serial_prefix(1).should == "email"
164
+ end
165
+ it "handles dNSName" do
166
+ R509::ASN1::GeneralName.map_tag_to_serial_prefix(2).should == "DNS"
167
+ end
168
+ it "handles x400Address" do
169
+ expect { R509::ASN1::GeneralName.map_tag_to_serial_prefix(3) }.to raise_error(R509::R509Error)
170
+ end
171
+ it "handles directoryName" do
172
+ R509::ASN1::GeneralName.map_tag_to_serial_prefix(4).should == "dirName"
173
+ end
174
+ it "handles ediPartyName" do
175
+ expect { R509::ASN1::GeneralName.map_tag_to_serial_prefix(5) }.to raise_error(R509::R509Error)
176
+ end
177
+ it "handles uniformResourceIdentifier" do
178
+ R509::ASN1::GeneralName.map_tag_to_serial_prefix(6).should == "URI"
179
+ end
180
+ it "handles iPAddress" do
181
+ R509::ASN1::GeneralName.map_tag_to_serial_prefix(7).should == "IP"
182
+ end
183
+ it "handles registeredID" do
184
+ expect { R509::ASN1::GeneralName.map_tag_to_serial_prefix(8) }.to raise_error(R509::R509Error)
185
+ end
186
+ end
187
+ it "handles rfc822Name" do
188
+ der = "\x81\u0011myemail@email.com"
189
+ asn = OpenSSL::ASN1.decode der
190
+ gn = R509::ASN1::GeneralName.new(asn)
191
+ gn.type.should == :rfc822Name
192
+ gn.value.should == 'myemail@email.com'
193
+ end
194
+ it "handles dNSName" do
195
+ der = "\x82\u000Ewww.test.local"
196
+ asn = OpenSSL::ASN1.decode der
197
+ gn = R509::ASN1::GeneralName.new(asn)
198
+ gn.type.should == :dNSName
199
+ gn.value.should == 'www.test.local'
200
+ end
201
+ it "handles uniformResourceIdentifier" do
202
+ der = "\x86\u001Fhttp://www.test.local/subca.crl"
203
+ asn = OpenSSL::ASN1.decode der
204
+ gn = R509::ASN1::GeneralName.new(asn)
205
+ gn.type.should == :uniformResourceIdentifier
206
+ gn.value.should == "http://www.test.local/subca.crl"
207
+ end
208
+ it "handles iPAddress v4" do
209
+ der = "\x87\u0004\n\u0001\u0002\u0003"
210
+ asn = OpenSSL::ASN1.decode der
211
+ gn = R509::ASN1::GeneralName.new(asn)
212
+ gn.type.should == :iPAddress
213
+ gn.value.should == '10.1.2.3'
214
+ end
215
+ it "handles iPAddress v6" do
216
+ der = "\x87\x10\x00\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
217
+ asn = OpenSSL::ASN1.decode der
218
+ gn = R509::ASN1::GeneralName.new(asn)
219
+ gn.type.should == :iPAddress
220
+ gn.value.should == 'ff::'
221
+ end
222
+ it "handles iPAddress v4 with netmask" do
223
+ der = "\x87\b\n\x01\x02\x03\xFF\xFF\xFF\xFF"
224
+ asn = OpenSSL::ASN1.decode der
225
+ gn = R509::ASN1::GeneralName.new(asn)
226
+ gn.type.should == :iPAddress
227
+ gn.value.should == '10.1.2.3/255.255.255.255'
228
+ end
229
+ it "handles iPAddress v6 with netmask" do
230
+ der = "\x87 \x00\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\x00\xFF\x00\xFF\x00\xFF\x00\xFF\x00\xFF\x00\xFF\x00\xFF"
231
+ asn = OpenSSL::ASN1.decode der
232
+ gn = R509::ASN1::GeneralName.new(asn)
233
+ gn.type.should == :iPAddress
234
+ gn.value.should == 'ff::/ff:ff:ff:ff:ff:ff:ff:ff'
235
+ end
236
+ it "handles directoryName" do
237
+ der = "\xA4`0^1\v0\t\u0006\u0003U\u0004\u0006\u0013\u0002US1\u00110\u000F\u0006\u0003U\u0004\b\f\bIllinois1\u00100\u000E\u0006\u0003U\u0004\a\f\aChicago1\u00180\u0016\u0006\u0003U\u0004\n\f\u000FRuby CA Project1\u00100\u000E\u0006\u0003U\u0004\u0003\f\aTest CA"
238
+ asn = OpenSSL::ASN1.decode der
239
+ gn = R509::ASN1::GeneralName.new(asn)
240
+ gn.type.should == :directoryName
241
+ gn.value.to_s.should == '/C=US/ST=Illinois/L=Chicago/O=Ruby CA Project/CN=Test CA'
242
+ end
243
+ it "errors on unimplemented type" do
244
+ # otherName type
245
+ der = "\xA0\u0014\u0006\u0003*\u0003\u0004\xA0\r\u0016\vHello World"
246
+ asn = OpenSSL::ASN1.decode der
247
+ expect { R509::ASN1::GeneralName.new(asn) }.to raise_error(R509::R509Error, "Unimplemented GeneralName tag: 0. At this time R509 does not support GeneralName types other than rfc822Name, dNSName, uniformResourceIdentifier, iPAddress, and directoryName")
248
+ end
249
+ end
250
+
251
+ describe R509::ASN1::GeneralNames do
252
+ it "adds items of allowed type to the object" do
253
+ asn = OpenSSL::ASN1.decode "\x82\u000Ewww.test.local"
254
+ asn2 = OpenSSL::ASN1.decode "\x81\u0011myemail@email.com"
255
+ asn3 = OpenSSL::ASN1.decode "\x82\u000Ewww.text.local"
256
+ gns = R509::ASN1::GeneralNames.new
257
+ gns.add_item(asn)
258
+ gns.add_item(asn2)
259
+ gns.add_item(asn3)
260
+ gns.dns_names.should == ["www.test.local","www.text.local"]
261
+ gns.rfc_822_names.should == ["myemail@email.com"]
262
+ end
263
+ it "errors on unimplemented type" do
264
+ # otherName type
265
+ gns = R509::ASN1::GeneralNames.new
266
+ der = "\xA0\u0014\u0006\u0003*\u0003\u0004\xA0\r\u0016\vHello World"
267
+ asn = OpenSSL::ASN1.decode der
268
+ expect { gns.add_item(asn) }.to raise_error(R509::R509Error, "Unimplemented GeneralName tag: 0. At this time R509 does not support GeneralName types other than rfc822Name, dNSName, uniformResourceIdentifier, iPAddress, and directoryName")
269
+ end
270
+ it "preserves order" do
271
+ asn = OpenSSL::ASN1.decode "\x82\u000Ewww.test.local"
272
+ asn2 = OpenSSL::ASN1.decode "\x81\u0011myemail@email.com"
273
+ asn3 = OpenSSL::ASN1.decode "\x82\u000Ewww.text.local"
274
+ gns = R509::ASN1::GeneralNames.new
275
+ gns.add_item(asn)
276
+ gns.add_item(asn2)
277
+ gns.add_item(asn3)
278
+ gns.names.count.should == 3
279
+ gns.names[0].type.should == :dNSName
280
+ gns.names[0].value.should == "www.test.local"
281
+ gns.names[1].type.should == :rfc822Name
282
+ gns.names[1].value.should == "myemail@email.com"
283
+ gns.names[2].type.should == :dNSName
284
+ gns.names[2].value.should == "www.text.local"
285
+ end
286
+
287
+ it "allows #uniq-ing of #names" do
288
+ gns = R509::ASN1::GeneralNames.new
289
+ gns.create_item(:tag => 1, :value => "test")
290
+ gns.create_item(:tag => 1, :value => "test")
291
+ gns.names.count.should == 2
292
+ gns.names.uniq.count.should == 1
293
+ end
294
+
295
+ it "errors with invalid params to #create_item" do
296
+ gns = R509::ASN1::GeneralNames.new
297
+ expect { gns.create_item({}) }.to raise_error(ArgumentError,'Must be a hash with (:tag or :type) and :value nodes')
298
+ end
299
+
300
+ it "allows addition of directoryNames with #create_item passing existing subject object" do
301
+ gns = R509::ASN1::GeneralNames.new
302
+ s = R509::Subject.new([['C','US'],['L','locality']])
303
+ gns.directory_names.size.should == 0
304
+ gns.create_item( :tag => 4, :value => s )
305
+ gns.directory_names.size.should == 1
306
+ end
307
+ it "allows addition of directoryNames with #create_item passing array" do
308
+ gns = R509::ASN1::GeneralNames.new
309
+ gns.directory_names.size.should == 0
310
+ gns.create_item( :tag => 4, :value => [['C','US'],['L','locality']] )
311
+ gns.directory_names.size.should == 1
312
+ end
313
+ end
314
+
315
+ describe R509::ASN1::PolicyInformation do
316
+ it "loads data with a policy oid but no qualifiers" do
317
+ data = OpenSSL::ASN1.decode "0\r\u0006\v`\x86H\u0001\xE09\u0001\u0002\u0003\u0004\u0001"
318
+ pi = R509::ASN1::PolicyInformation.new(data)
319
+ pi.policy_identifier.should == '2.16.840.1.12345.1.2.3.4.1'
320
+ pi.policy_qualifiers.should be_nil
321
+ end
322
+ it "loads data with a policy oid and a single qualifier" do
323
+ data = OpenSSL::ASN1.decode "0U\u0006\v`\x86H\u0001\xE09\u0001\u0002\u0003\u0004\u00010F0\"\u0006\b+\u0006\u0001\u0005\u0005\a\u0002\u0001\u0016\u0016http://example.com/cps0 \u0006\b+\u0006\u0001\u0005\u0005\a\u0002\u0001\u0016\u0014http://other.com/cps"
324
+ pi = R509::ASN1::PolicyInformation.new(data)
325
+ pi.policy_identifier.should == '2.16.840.1.12345.1.2.3.4.1'
326
+ pi.policy_qualifiers.cps_uris.empty?.should == false
327
+ pi.policy_qualifiers.user_notices.empty?.should == true
328
+ end
329
+ it "loads data with a policy oid and multiple qualifiers" do
330
+ data = OpenSSL::ASN1.decode "0\x81\x94\u0006\n`\x86H\u0001\x86\x8D\u001F\u0015\x81k0\x81\x850#\u0006\b+\u0006\u0001\u0005\u0005\a\u0002\u0001\u0016\u0017http://example.com/cps20;\u0006\b+\u0006\u0001\u0005\u0005\a\u0002\u00020/0\u0018\u0016\vanother org0\t\u0002\u0001\u0003\u0002\u0001\u0002\u0002\u0001\u0001\u001A\u0013this is a bad thing0!\u0006\b+\u0006\u0001\u0005\u0005\a\u0002\u00020\u0015\u001A\u0013another user notice"
331
+ pi = R509::ASN1::PolicyInformation.new(data)
332
+ pi.policy_identifier.should == '2.16.840.1.99999.21.235'
333
+ pi.policy_qualifiers.cps_uris.empty?.should == false
334
+ pi.policy_qualifiers.user_notices.empty?.should == false
335
+ end
336
+ end
337
+
338
+ describe R509::ASN1::PolicyQualifiers do
339
+ before :each do
340
+ @pq = R509::ASN1::PolicyQualifiers.new
341
+ end
342
+
343
+ it "initializes empty cps_uris and user_notices" do
344
+ @pq.should_not be_nil
345
+ @pq.cps_uris.empty?.should == true
346
+ @pq.user_notices.empty?.should == true
347
+ end
348
+ it "parses a cps qualifier and adds it to cps_uris" do
349
+ data = OpenSSL::ASN1.decode "0#\u0006\b+\u0006\u0001\u0005\u0005\a\u0002\u0001\u0016\u0017http://example.com/cps2"
350
+ @pq.parse(data)
351
+ @pq.cps_uris.should == ['http://example.com/cps2']
352
+ @pq.user_notices.should == []
353
+ end
354
+ it "parses a user notice and adds it to user_notices" do
355
+ data = OpenSSL::ASN1.decode "0!\u0006\b+\u0006\u0001\u0005\u0005\a\u0002\u00020\u0015\u001A\u0013another user notice"
356
+ @pq.parse(data)
357
+ @pq.cps_uris.should == []
358
+ @pq.user_notices.count.should == 1
359
+ end
360
+ end
361
+
362
+ describe R509::ASN1::UserNotice do
363
+ it "loads data with both a notice reference and explicit text" do
364
+ data = OpenSSL::ASN1.decode "0\u001F0\u0016\u0016\u0006my org0\f\u0002\u0001\u0001\u0002\u0001\u0002\u0002\u0001\u0003\u0002\u0001\u0004\u001A\u0005thing"
365
+ un = R509::ASN1::UserNotice.new(data)
366
+ un.notice_reference.should_not be_nil
367
+ un.explicit_text.should == 'thing'
368
+ end
369
+ it "loads data with a notice reference" do
370
+ data = OpenSSL::ASN1.decode "0\u00180\u0016\u0016\u0006my org0\f\u0002\u0001\u0001\u0002\u0001\u0002\u0002\u0001\u0003\u0002\u0001\u0004"
371
+ un = R509::ASN1::UserNotice.new(data)
372
+ un.notice_reference.should_not be_nil
373
+ un.explicit_text.should be_nil
374
+ end
375
+ it "loads data with an explicit text" do
376
+ data = OpenSSL::ASN1.decode "0\a\u001A\u0005thing"
377
+ un = R509::ASN1::UserNotice.new(data)
378
+ un.notice_reference.should be_nil
379
+ un.explicit_text.should == 'thing'
380
+ end
381
+ end
382
+
383
+ describe R509::ASN1::NoticeReference do
384
+ it "loads data with an org and no notice numbers" do
385
+ data = OpenSSL::ASN1.decode "0\n\u0016\u0006my org0\u0000"
386
+ nr = R509::ASN1::NoticeReference.new(data)
387
+ nr.organization.should == 'my org'
388
+ nr.notice_numbers.should == []
389
+ end
390
+ it "loads data with an org and 1 notice number" do
391
+ data = OpenSSL::ASN1.decode "0\r\u0016\u0006my org0\u0003\u0002\u0001\u0001"
392
+ nr = R509::ASN1::NoticeReference.new(data)
393
+ nr.organization.should == 'my org'
394
+ nr.notice_numbers.should == [1]
395
+ end
396
+ it "loads data with an org and more than 1 notice number" do
397
+ data = OpenSSL::ASN1.decode "0\u0016\u0016\u0006my org0\f\u0002\u0001\u0001\u0002\u0001\u0002\u0002\u0001\u0003\u0002\u0001\u0004"
398
+ nr = R509::ASN1::NoticeReference.new(data)
399
+ nr.organization.should == 'my org'
400
+ nr.notice_numbers.should == [1,2,3,4]
401
+ end
402
+ end