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
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