r509 0.8.1 → 0.9
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +343 -151
- data/Rakefile +26 -23
- data/bin/r509 +126 -112
- data/bin/r509-parse +24 -24
- data/doc/R509.html +169 -7
- data/doc/R509/ASN1.html +370 -0
- data/doc/R509/ASN1/GeneralName.html +1121 -0
- data/doc/R509/ASN1/GeneralNames.html +843 -0
- data/doc/R509/ASN1/NoticeReference.html +392 -0
- data/doc/R509/ASN1/PolicyInformation.html +387 -0
- data/doc/R509/ASN1/PolicyQualifiers.html +455 -0
- data/doc/R509/ASN1/UserNotice.html +386 -0
- data/doc/R509/{Crl.html → CRL.html} +7 -7
- data/doc/R509/CRL/Administrator.html +1559 -0
- data/doc/R509/{Crl/Parser.html → CRL/SignedList.html} +501 -210
- data/doc/R509/{Csr.html → CSR.html} +444 -314
- data/doc/R509/Cert.html +866 -617
- data/doc/R509/Cert/Extensions.html +52 -41
- data/doc/R509/Cert/Extensions/AuthorityInfoAccess.html +70 -35
- data/doc/R509/Cert/Extensions/AuthorityKeyIdentifier.html +387 -4
- data/doc/R509/Cert/Extensions/BasicConstraints.html +61 -25
- data/doc/R509/Cert/Extensions/CRLDistributionPoints.html +354 -0
- data/doc/R509/Cert/Extensions/CertificatePolicies.html +340 -0
- data/doc/R509/Cert/Extensions/ExtendedKeyUsage.html +440 -49
- data/doc/R509/Cert/Extensions/{CrlDistributionPoints.html → InhibitAnyPolicy.html} +52 -35
- data/doc/R509/Cert/Extensions/KeyUsage.html +247 -121
- data/doc/R509/Cert/Extensions/NameConstraints.html +445 -0
- data/doc/R509/Cert/Extensions/OCSPNoCheck.html +239 -0
- data/doc/R509/Cert/Extensions/PolicyConstraints.html +424 -0
- data/doc/R509/Cert/Extensions/SubjectAlternativeName.html +437 -62
- data/doc/R509/Cert/Extensions/SubjectKeyIdentifier.html +52 -10
- data/doc/R509/CertificateAuthority.html +4 -4
- data/doc/R509/CertificateAuthority/Signer.html +154 -187
- data/doc/R509/Config.html +6 -6
- data/doc/R509/Config/{CaConfig.html → CAConfig.html} +451 -348
- data/doc/R509/Config/{CaConfigPool.html → CAConfigPool.html} +47 -47
- data/doc/R509/Config/CAProfile.html +1015 -0
- data/doc/R509/Config/SubjectItemPolicy.html +86 -86
- data/doc/R509/IOHelpers.html +22 -22
- data/doc/R509/MessageDigest.html +14 -14
- data/doc/R509/NameSanitizer.html +53 -53
- data/doc/R509/{Ocsp.html → OCSP.html} +9 -9
- data/doc/R509/{Ocsp → OCSP}/Request.html +7 -7
- data/doc/R509/{Ocsp → OCSP}/Request/Nonce.html +56 -11
- data/doc/R509/{Ocsp → OCSP}/Response.html +44 -44
- data/doc/R509/{OidMapper.html → OIDMapper.html} +23 -39
- data/doc/R509/PrivateKey.html +415 -168
- data/doc/R509/R509Error.html +3 -3
- data/doc/R509/{Spki.html → SPKI.html} +354 -192
- data/doc/R509/Subject.html +224 -113
- data/doc/R509/Validity.html +27 -5
- data/doc/R509/Validity/Checker.html +13 -13
- data/doc/R509/Validity/DefaultChecker.html +13 -13
- data/doc/R509/Validity/DefaultWriter.html +14 -14
- data/doc/R509/Validity/Status.html +39 -39
- data/doc/R509/Validity/Writer.html +18 -18
- data/doc/_index.html +138 -35
- data/doc/class_list.html +1 -1
- data/doc/css/style.css +10 -0
- data/doc/file.README.html +368 -171
- data/doc/file.r509.html +92 -69
- data/doc/frames.html +1 -1
- data/doc/index.html +368 -171
- data/doc/method_list.html +910 -390
- data/doc/top-level-namespace.html +3 -3
- data/lib/r509.rb +32 -16
- data/lib/r509/asn1.rb +375 -0
- data/lib/r509/cert.rb +381 -364
- data/lib/r509/cert/extensions.rb +443 -76
- data/lib/r509/certificate_authority.rb +407 -0
- data/lib/r509/config.rb +547 -351
- data/lib/r509/crl.rb +336 -366
- data/lib/r509/csr.rb +278 -289
- data/lib/r509/ec-hack.rb +37 -0
- data/lib/r509/exceptions.rb +3 -3
- data/lib/r509/io_helpers.rb +44 -44
- data/lib/r509/message_digest.rb +53 -0
- data/lib/r509/ocsp.rb +80 -70
- data/lib/r509/oid_mapper.rb +32 -0
- data/lib/r509/private_key.rb +228 -0
- data/lib/r509/spki.rb +145 -93
- data/lib/r509/subject.rb +203 -110
- data/lib/r509/validity.rb +70 -68
- data/lib/r509/version.rb +2 -2
- data/r509.yaml +92 -69
- data/spec/asn1_spec.rb +402 -0
- data/spec/cert/extensions_spec.rb +957 -494
- data/spec/cert_spec.rb +382 -307
- data/spec/certificate_authority_spec.rb +668 -250
- data/spec/config_spec.rb +515 -302
- data/spec/crl_spec.rb +197 -198
- data/spec/csr_spec.rb +334 -289
- data/spec/fixtures.rb +247 -171
- data/spec/fixtures/cert1.der +0 -0
- data/spec/fixtures/cert1.pem +0 -0
- data/spec/fixtures/cert1_public_key_modulus.txt +0 -0
- data/spec/fixtures/cert3.p12 +0 -0
- data/spec/fixtures/cert3.pem +0 -0
- data/spec/fixtures/cert3_key.pem +0 -0
- data/spec/fixtures/cert3_key_des3.pem +0 -0
- data/spec/fixtures/cert4.pem +0 -0
- data/spec/fixtures/cert5.pem +0 -0
- data/spec/fixtures/cert6.pem +0 -0
- data/spec/fixtures/cert_expired.pem +0 -0
- data/spec/fixtures/cert_inhibit.pem +24 -0
- data/spec/fixtures/cert_name_constraints.pem +29 -0
- data/spec/fixtures/cert_not_yet_valid.pem +0 -0
- data/spec/fixtures/cert_ocsp_no_check.pem +18 -0
- data/spec/fixtures/cert_policy_constraints.pem +31 -0
- data/spec/fixtures/cert_san.pem +0 -0
- data/spec/fixtures/cert_san2.pem +0 -0
- data/spec/fixtures/cert_unknown_extension.pem +28 -0
- data/spec/fixtures/config_pool_test_minimal.yaml +11 -11
- data/spec/fixtures/config_test.yaml +54 -36
- data/spec/fixtures/config_test_dsa.yaml +35 -0
- data/spec/fixtures/config_test_ec.yaml +35 -0
- data/spec/fixtures/config_test_engine_key.yaml +5 -5
- data/spec/fixtures/config_test_engine_no_key_name.yaml +4 -4
- data/spec/fixtures/config_test_minimal.yaml +4 -4
- data/spec/fixtures/config_test_password.yaml +5 -5
- data/spec/fixtures/config_test_various.yaml +111 -74
- data/spec/fixtures/crl_list_file.txt +0 -0
- data/spec/fixtures/crl_with_reason.pem +0 -0
- data/spec/fixtures/csr1.der +0 -0
- data/spec/fixtures/csr1.pem +0 -0
- data/spec/fixtures/csr1_key.der +0 -0
- data/spec/fixtures/csr1_key.pem +0 -0
- data/spec/fixtures/csr1_key_encrypted_des3.pem +0 -0
- data/spec/fixtures/csr1_newlines.pem +0 -0
- data/spec/fixtures/csr1_no_begin_end.pem +0 -0
- data/spec/fixtures/csr1_public_key_modulus.txt +0 -0
- data/spec/fixtures/csr2.pem +0 -0
- data/spec/fixtures/csr2_key.pem +0 -0
- data/spec/fixtures/csr3.pem +0 -0
- data/spec/fixtures/csr4.pem +0 -0
- data/spec/fixtures/csr_dsa.pem +0 -0
- data/spec/fixtures/csr_invalid_signature.pem +0 -0
- data/spec/fixtures/dsa_key.pem +0 -0
- data/spec/fixtures/dsa_root.cer +28 -0
- data/spec/fixtures/dsa_root.key +20 -0
- data/spec/fixtures/ec_csr2.der +0 -0
- data/spec/fixtures/ec_csr2.pem +8 -0
- data/spec/fixtures/ec_key1.der +0 -0
- data/spec/fixtures/ec_key1.pem +6 -0
- data/spec/fixtures/ec_key1_encrypted.pem +9 -0
- data/spec/fixtures/ec_key2.pem +6 -0
- data/spec/fixtures/hmacsha1.sig +1 -0
- data/spec/fixtures/hmacsha512.sig +1 -0
- data/spec/fixtures/key4.pem +0 -0
- data/spec/fixtures/key4_encrypted_des3.pem +0 -0
- data/spec/fixtures/missing_key_identifier_ca.cer +0 -0
- data/spec/fixtures/missing_key_identifier_ca.key +0 -0
- data/spec/fixtures/ocsptest.r509.local.pem +0 -0
- data/spec/fixtures/ocsptest.r509.local_ocsp_request.der +0 -0
- data/spec/fixtures/ocsptest2.r509.local.pem +0 -0
- data/spec/fixtures/second_ca.cer +0 -0
- data/spec/fixtures/second_ca.key +0 -0
- data/spec/fixtures/spkac.der +0 -0
- data/spec/fixtures/spkac.txt +0 -0
- data/spec/fixtures/spkac_dsa.txt +1 -1
- data/spec/fixtures/spkac_dsa_no_verify.txt +1 -0
- data/spec/fixtures/spkac_ec.txt +1 -0
- data/spec/fixtures/spkac_rsa_newlines.txt +13 -0
- data/spec/fixtures/stca.pem +0 -0
- data/spec/fixtures/stca_ocsp_request.der +0 -0
- data/spec/fixtures/stca_ocsp_response.der +0 -0
- data/spec/fixtures/test1.csr +0 -0
- data/spec/fixtures/test_ca.cer +0 -0
- data/spec/fixtures/test_ca.key +0 -0
- data/spec/fixtures/test_ca.p12 +0 -0
- data/spec/fixtures/test_ca_des3.key +0 -0
- data/spec/fixtures/test_ca_ec.cer +14 -0
- data/spec/fixtures/test_ca_ec.key +6 -0
- data/spec/fixtures/test_ca_ec_ee.cer +22 -0
- data/spec/fixtures/test_ca_ec_ee.key +6 -0
- data/spec/fixtures/test_ca_ocsp.cer +0 -0
- data/spec/fixtures/test_ca_ocsp.key +0 -0
- data/spec/fixtures/test_ca_ocsp.p12 +0 -0
- data/spec/fixtures/test_ca_ocsp_chain.txt +0 -0
- data/spec/fixtures/test_ca_ocsp_response.der +0 -0
- data/spec/fixtures/test_ca_subroot.cer +0 -0
- data/spec/fixtures/test_ca_subroot.key +0 -0
- data/spec/fixtures/test_ca_subroot_ocsp.cer +0 -0
- data/spec/fixtures/test_ca_subroot_ocsp.key +0 -0
- data/spec/fixtures/test_ca_subroot_ocsp_response.der +0 -0
- data/spec/fixtures/unknown_oid.csr +0 -0
- data/spec/message_digest_spec.rb +104 -84
- data/spec/ocsp_spec.rb +105 -105
- data/spec/oid_mapper_spec.rb +21 -21
- data/spec/private_key_spec.rb +275 -0
- data/spec/r509_spec.rb +35 -0
- data/spec/spec_helper.rb +15 -6
- data/spec/spki_spec.rb +221 -142
- data/spec/subject_spec.rb +232 -164
- data/spec/validity_spec.rb +91 -91
- metadata +79 -25
- data/doc/R509/Config/CaProfile.html +0 -651
- data/doc/R509/Crl/Administrator.html +0 -2073
- data/lib/r509/certificateauthority.rb +0 -290
- data/lib/r509/messagedigest.rb +0 -49
- data/lib/r509/oidmapper.rb +0 -32
- data/lib/r509/privatekey.rb +0 -185
- 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
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
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
|
-
|
11
|
-
|
12
|
-
|
12
|
+
#data about the status of a certificate
|
13
|
+
class Status
|
14
|
+
attr_reader :status, :revocation_time, :revocation_reason
|
13
15
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
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
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
21
|
+
if (@status == R509::Validity::REVOKED and @revocation_time.nil?)
|
22
|
+
@revocation_time = Time.now.to_i
|
23
|
+
end
|
24
|
+
end
|
23
25
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
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
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
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
|
-
|
46
|
-
|
47
|
-
|
47
|
+
def revoke(issuer, serial, reason)
|
48
|
+
raise NotImplementedError, "You must call #revoke on a subclass of Writer"
|
49
|
+
end
|
48
50
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
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
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
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
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
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
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
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
|
-
|
76
|
-
|
77
|
-
end
|
77
|
+
def is_available?
|
78
|
+
true
|
78
79
|
end
|
80
|
+
end
|
79
81
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
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
|
-
|
86
|
-
|
87
|
+
def revoke(issuer, serial, reason)
|
88
|
+
end
|
87
89
|
|
88
|
-
|
89
|
-
|
90
|
-
end
|
90
|
+
def is_available?
|
91
|
+
true
|
91
92
|
end
|
93
|
+
end
|
92
94
|
end
|
data/lib/r509/version.rb
CHANGED
data/r509.yaml
CHANGED
@@ -1,73 +1,96 @@
|
|
1
1
|
certificate_authorities: {
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
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
|