r509 0.8
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.
- data/README.md +447 -0
- data/Rakefile +38 -0
- data/bin/r509 +96 -0
- data/bin/r509-parse +35 -0
- data/doc/R509.html +154 -0
- data/doc/R509/Cert.html +3954 -0
- data/doc/R509/Cert/Extensions.html +360 -0
- data/doc/R509/Cert/Extensions/AuthorityInfoAccess.html +391 -0
- data/doc/R509/Cert/Extensions/AuthorityKeyIdentifier.html +148 -0
- data/doc/R509/Cert/Extensions/BasicConstraints.html +482 -0
- data/doc/R509/Cert/Extensions/CrlDistributionPoints.html +316 -0
- data/doc/R509/Cert/Extensions/ExtendedKeyUsage.html +780 -0
- data/doc/R509/Cert/Extensions/KeyUsage.html +1230 -0
- data/doc/R509/Cert/Extensions/SubjectAlternativeName.html +467 -0
- data/doc/R509/Cert/Extensions/SubjectKeyIdentifier.html +216 -0
- data/doc/R509/CertificateAuthority.html +126 -0
- data/doc/R509/CertificateAuthority/Signer.html +855 -0
- data/doc/R509/Config.html +127 -0
- data/doc/R509/Config/CaConfig.html +2144 -0
- data/doc/R509/Config/CaConfigPool.html +599 -0
- data/doc/R509/Config/CaProfile.html +656 -0
- data/doc/R509/Config/SubjectItemPolicy.html +578 -0
- data/doc/R509/Crl.html +126 -0
- data/doc/R509/Crl/Administrator.html +2077 -0
- data/doc/R509/Crl/Parser.html +1224 -0
- data/doc/R509/Csr.html +2248 -0
- data/doc/R509/IOHelpers.html +564 -0
- data/doc/R509/MessageDigest.html +396 -0
- data/doc/R509/NameSanitizer.html +319 -0
- data/doc/R509/Ocsp.html +128 -0
- data/doc/R509/Ocsp/Request.html +126 -0
- data/doc/R509/Ocsp/Request/Nonce.html +160 -0
- data/doc/R509/Ocsp/Response.html +837 -0
- data/doc/R509/OidMapper.html +393 -0
- data/doc/R509/PrivateKey.html +1647 -0
- data/doc/R509/R509Error.html +134 -0
- data/doc/R509/Spki.html +1424 -0
- data/doc/R509/Subject.html +836 -0
- data/doc/R509/Validity.html +160 -0
- data/doc/R509/Validity/Checker.html +320 -0
- data/doc/R509/Validity/DefaultChecker.html +283 -0
- data/doc/R509/Validity/DefaultWriter.html +330 -0
- data/doc/R509/Validity/Status.html +561 -0
- data/doc/R509/Validity/Writer.html +394 -0
- data/doc/_index.html +501 -0
- data/doc/class_list.html +53 -0
- data/doc/css/common.css +1 -0
- data/doc/css/full_list.css +57 -0
- data/doc/css/style.css +328 -0
- data/doc/file.README.html +534 -0
- data/doc/file.r509.html +149 -0
- data/doc/file_list.html +58 -0
- data/doc/frames.html +28 -0
- data/doc/index.html +534 -0
- data/doc/js/app.js +208 -0
- data/doc/js/full_list.js +173 -0
- data/doc/js/jquery.js +4 -0
- data/doc/methods_list.html +1932 -0
- data/doc/top-level-namespace.html +112 -0
- data/lib/r509.rb +22 -0
- data/lib/r509/cert.rb +414 -0
- data/lib/r509/cert/extensions.rb +309 -0
- data/lib/r509/certificateauthority.rb +290 -0
- data/lib/r509/config.rb +407 -0
- data/lib/r509/crl.rb +379 -0
- data/lib/r509/csr.rb +324 -0
- data/lib/r509/exceptions.rb +5 -0
- data/lib/r509/io_helpers.rb +52 -0
- data/lib/r509/messagedigest.rb +49 -0
- data/lib/r509/ocsp.rb +85 -0
- data/lib/r509/oidmapper.rb +32 -0
- data/lib/r509/privatekey.rb +185 -0
- data/lib/r509/spki.rb +112 -0
- data/lib/r509/subject.rb +133 -0
- data/lib/r509/validity.rb +92 -0
- data/lib/r509/version.rb +4 -0
- data/r509.yaml +73 -0
- data/spec/cert/extensions_spec.rb +632 -0
- data/spec/cert_spec.rb +321 -0
- data/spec/certificate_authority_spec.rb +260 -0
- data/spec/config_spec.rb +349 -0
- data/spec/crl_spec.rb +215 -0
- data/spec/csr_spec.rb +302 -0
- data/spec/fixtures.rb +233 -0
- data/spec/fixtures/cert1.der +0 -0
- data/spec/fixtures/cert1.pem +24 -0
- data/spec/fixtures/cert1_public_key_modulus.txt +1 -0
- data/spec/fixtures/cert3.p12 +0 -0
- data/spec/fixtures/cert3.pem +28 -0
- data/spec/fixtures/cert3_key.pem +27 -0
- data/spec/fixtures/cert3_key_des3.pem +30 -0
- data/spec/fixtures/cert4.pem +14 -0
- data/spec/fixtures/cert5.pem +30 -0
- data/spec/fixtures/cert6.pem +26 -0
- data/spec/fixtures/cert_expired.pem +26 -0
- data/spec/fixtures/cert_not_yet_valid.pem +26 -0
- data/spec/fixtures/cert_san.pem +27 -0
- data/spec/fixtures/cert_san2.pem +22 -0
- data/spec/fixtures/config_pool_test_minimal.yaml +15 -0
- data/spec/fixtures/config_test.yaml +41 -0
- data/spec/fixtures/config_test_engine_key.yaml +7 -0
- data/spec/fixtures/config_test_engine_no_key_name.yaml +6 -0
- data/spec/fixtures/config_test_minimal.yaml +7 -0
- data/spec/fixtures/config_test_password.yaml +7 -0
- data/spec/fixtures/config_test_various.yaml +100 -0
- data/spec/fixtures/crl_list_file.txt +1 -0
- data/spec/fixtures/crl_with_reason.pem +17 -0
- data/spec/fixtures/csr1.der +0 -0
- data/spec/fixtures/csr1.pem +17 -0
- data/spec/fixtures/csr1_key.der +0 -0
- data/spec/fixtures/csr1_key.pem +27 -0
- data/spec/fixtures/csr1_key_encrypted_des3.pem +30 -0
- data/spec/fixtures/csr1_newlines.pem +32 -0
- data/spec/fixtures/csr1_no_begin_end.pem +15 -0
- data/spec/fixtures/csr1_public_key_modulus.txt +1 -0
- data/spec/fixtures/csr2.pem +15 -0
- data/spec/fixtures/csr2_key.pem +27 -0
- data/spec/fixtures/csr3.pem +16 -0
- data/spec/fixtures/csr4.pem +25 -0
- data/spec/fixtures/csr_dsa.pem +15 -0
- data/spec/fixtures/csr_invalid_signature.pem +13 -0
- data/spec/fixtures/dsa_key.pem +20 -0
- data/spec/fixtures/key4.pem +27 -0
- data/spec/fixtures/key4_encrypted_des3.pem +30 -0
- data/spec/fixtures/missing_key_identifier_ca.cer +21 -0
- data/spec/fixtures/missing_key_identifier_ca.key +27 -0
- data/spec/fixtures/ocsptest.r509.local.pem +27 -0
- data/spec/fixtures/ocsptest.r509.local_ocsp_request.der +0 -0
- data/spec/fixtures/ocsptest2.r509.local.pem +27 -0
- data/spec/fixtures/second_ca.cer +26 -0
- data/spec/fixtures/second_ca.key +27 -0
- data/spec/fixtures/spkac.der +0 -0
- data/spec/fixtures/spkac.txt +1 -0
- data/spec/fixtures/spkac_dsa.txt +1 -0
- data/spec/fixtures/stca.pem +22 -0
- data/spec/fixtures/stca_ocsp_request.der +0 -0
- data/spec/fixtures/stca_ocsp_response.der +0 -0
- data/spec/fixtures/test1.csr +17 -0
- data/spec/fixtures/test_ca.cer +22 -0
- data/spec/fixtures/test_ca.key +28 -0
- data/spec/fixtures/test_ca.p12 +0 -0
- data/spec/fixtures/test_ca_des3.key +30 -0
- data/spec/fixtures/test_ca_ocsp.cer +26 -0
- data/spec/fixtures/test_ca_ocsp.key +27 -0
- data/spec/fixtures/test_ca_ocsp.p12 +0 -0
- data/spec/fixtures/test_ca_ocsp_chain.txt +48 -0
- data/spec/fixtures/test_ca_ocsp_response.der +0 -0
- data/spec/fixtures/test_ca_subroot.cer +26 -0
- data/spec/fixtures/test_ca_subroot.key +27 -0
- data/spec/fixtures/test_ca_subroot_ocsp.cer +25 -0
- data/spec/fixtures/test_ca_subroot_ocsp.key +27 -0
- data/spec/fixtures/test_ca_subroot_ocsp_response.der +0 -0
- data/spec/fixtures/unknown_oid.csr +17 -0
- data/spec/message_digest_spec.rb +89 -0
- data/spec/ocsp_spec.rb +111 -0
- data/spec/oid_mapper_spec.rb +31 -0
- data/spec/privatekey_spec.rb +198 -0
- data/spec/spec_helper.rb +14 -0
- data/spec/spki_spec.rb +157 -0
- data/spec/subject_spec.rb +203 -0
- data/spec/validity_spec.rb +98 -0
- metadata +257 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
|
2
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
3
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
|
4
|
+
<head>
|
|
5
|
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
|
6
|
+
<title>
|
|
7
|
+
Top Level Namespace
|
|
8
|
+
|
|
9
|
+
— Documentation by YARD 0.8.0
|
|
10
|
+
|
|
11
|
+
</title>
|
|
12
|
+
|
|
13
|
+
<link rel="stylesheet" href="css/style.css" type="text/css" media="screen" charset="utf-8" />
|
|
14
|
+
|
|
15
|
+
<link rel="stylesheet" href="css/common.css" type="text/css" media="screen" charset="utf-8" />
|
|
16
|
+
|
|
17
|
+
<script type="text/javascript" charset="utf-8">
|
|
18
|
+
hasFrames = window.top.frames.main ? true : false;
|
|
19
|
+
relpath = '';
|
|
20
|
+
framesUrl = "frames.html#!" + escape(window.location.href);
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
<script type="text/javascript" charset="utf-8" src="js/jquery.js"></script>
|
|
25
|
+
|
|
26
|
+
<script type="text/javascript" charset="utf-8" src="js/app.js"></script>
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
</head>
|
|
30
|
+
<body>
|
|
31
|
+
<div id="header">
|
|
32
|
+
<div id="menu">
|
|
33
|
+
|
|
34
|
+
<a href="_index.html">Index</a> »
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
<span class="title">Top Level Namespace</span>
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
<div class="noframes"><span class="title">(</span><a href="." target="_top">no frames</a><span class="title">)</span></div>
|
|
41
|
+
</div>
|
|
42
|
+
|
|
43
|
+
<div id="search">
|
|
44
|
+
|
|
45
|
+
<a class="full_list_link" id="class_list_link"
|
|
46
|
+
href="class_list.html">
|
|
47
|
+
Class List
|
|
48
|
+
</a>
|
|
49
|
+
|
|
50
|
+
<a class="full_list_link" id="method_list_link"
|
|
51
|
+
href="method_list.html">
|
|
52
|
+
Method List
|
|
53
|
+
</a>
|
|
54
|
+
|
|
55
|
+
<a class="full_list_link" id="file_list_link"
|
|
56
|
+
href="file_list.html">
|
|
57
|
+
File List
|
|
58
|
+
</a>
|
|
59
|
+
|
|
60
|
+
</div>
|
|
61
|
+
<div class="clear"></div>
|
|
62
|
+
</div>
|
|
63
|
+
|
|
64
|
+
<iframe id="search_frame"></iframe>
|
|
65
|
+
|
|
66
|
+
<div id="content"><h1>Top Level Namespace
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
</h1>
|
|
71
|
+
|
|
72
|
+
<dl class="box">
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
</dl>
|
|
82
|
+
<div class="clear"></div>
|
|
83
|
+
|
|
84
|
+
<h2>Defined Under Namespace</h2>
|
|
85
|
+
<p class="children">
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
<strong class="modules">Modules:</strong> <span class='object_link'><a href="R509.html" title="R509 (module)">R509</a></span>
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
</p>
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
</div>
|
|
104
|
+
|
|
105
|
+
<div id="footer">
|
|
106
|
+
Generated on Tue Oct 23 22:48:01 2012 by
|
|
107
|
+
<a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
|
|
108
|
+
0.8.0 (ruby-1.9.3).
|
|
109
|
+
</div>
|
|
110
|
+
|
|
111
|
+
</body>
|
|
112
|
+
</html>
|
data/lib/r509.rb
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# A module for building an easy to use CA. Includes CSR, Certificate, and CRL support.
|
|
2
|
+
module R509
|
|
3
|
+
require('r509/certificateauthority.rb')
|
|
4
|
+
require('r509/csr.rb')
|
|
5
|
+
require('r509/spki.rb')
|
|
6
|
+
require('r509/cert.rb')
|
|
7
|
+
require('r509/crl.rb')
|
|
8
|
+
require('r509/oidmapper.rb')
|
|
9
|
+
require('r509/ocsp.rb')
|
|
10
|
+
require('r509/config.rb')
|
|
11
|
+
require('r509/privatekey.rb')
|
|
12
|
+
require('r509/messagedigest.rb')
|
|
13
|
+
require('r509/subject.rb')
|
|
14
|
+
require('r509/validity.rb')
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
#add some global mappings we want available throughout r509
|
|
18
|
+
R509::OidMapper.batch_register([
|
|
19
|
+
{ :oid => "2.5.4.15", :short_name => "businessCategory" },
|
|
20
|
+
{ :oid => "1.3.6.1.4.1.311.60.2.1.2", :short_name => "jurisdictionOfIncorporationStateOrProvinceName" },
|
|
21
|
+
{ :oid => "1.3.6.1.4.1.311.60.2.1.3", :short_name => "jurisdictionOfIncorporationCountryName" }
|
|
22
|
+
])
|
data/lib/r509/cert.rb
ADDED
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
require 'openssl'
|
|
2
|
+
require 'r509/exceptions'
|
|
3
|
+
require 'r509/io_helpers'
|
|
4
|
+
require 'r509/cert/extensions'
|
|
5
|
+
|
|
6
|
+
module R509
|
|
7
|
+
# The primary certificate object.
|
|
8
|
+
class Cert
|
|
9
|
+
include R509::IOHelpers
|
|
10
|
+
|
|
11
|
+
attr_reader :cert, :key
|
|
12
|
+
|
|
13
|
+
# @option opts [String,OpenSSL::X509::Certificate] :cert a cert
|
|
14
|
+
# @option opts [R509::PrivateKey,String] :key optional private key to supply. either an unencrypted PEM/DER string or an R509::PrivateKey object (use the latter if you need password/hardware support)
|
|
15
|
+
# @option opts [String] :pkcs12 a PKCS12 object containing both key and cert
|
|
16
|
+
# @option opts [String] :password password for PKCS12 or private key (if supplied)
|
|
17
|
+
def initialize(opts={})
|
|
18
|
+
if not opts.kind_of?(Hash)
|
|
19
|
+
raise ArgumentError, 'Must provide a hash of options'
|
|
20
|
+
end
|
|
21
|
+
if opts.has_key?(:pkcs12) and ( opts.has_key?(:key) or opts.has_key?(:cert) )
|
|
22
|
+
raise ArgumentError, "When providing pkcs12, do not pass cert or key"
|
|
23
|
+
elsif opts.has_key?(:pkcs12)
|
|
24
|
+
pkcs12 = OpenSSL::PKCS12.new( opts[:pkcs12], opts[:password] )
|
|
25
|
+
parse_certificate(pkcs12.certificate)
|
|
26
|
+
@key = R509::PrivateKey.new( :key => pkcs12.key )
|
|
27
|
+
elsif not opts.has_key?(:cert)
|
|
28
|
+
raise ArgumentError, 'Must provide :cert or :pkcs12'
|
|
29
|
+
else
|
|
30
|
+
csr_check(opts[:cert])
|
|
31
|
+
parse_certificate(opts[:cert])
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
if opts.has_key?(:key)
|
|
35
|
+
if opts[:key].kind_of?(R509::PrivateKey)
|
|
36
|
+
@key = opts[:key]
|
|
37
|
+
else
|
|
38
|
+
@key = R509::PrivateKey.new( :key => opts[:key], :password => opts[:password] )
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
if not @key.nil?
|
|
42
|
+
if not @cert.public_key.to_s == @key.public_key.to_s then
|
|
43
|
+
raise R509Error, 'Key does not match cert.'
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Helper method to quickly load a cert from the filesystem
|
|
49
|
+
#
|
|
50
|
+
# @param [String] filename Path to file you want to load
|
|
51
|
+
# @return [R509::Cert] cert object
|
|
52
|
+
def self.load_from_file( filename )
|
|
53
|
+
return R509::Cert.new(:cert => IOHelpers.read_data(filename) )
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
# Converts the Cert into the PEM format
|
|
59
|
+
#
|
|
60
|
+
# @return [String] the Cert converted into PEM format.
|
|
61
|
+
def to_pem
|
|
62
|
+
if @cert.kind_of?(OpenSSL::X509::Certificate)
|
|
63
|
+
return @cert.to_pem.chomp
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
alias :to_s :to_pem
|
|
68
|
+
|
|
69
|
+
# Converts the Cert into the DER format
|
|
70
|
+
#
|
|
71
|
+
# @return [String] the Cert converted into DER format.
|
|
72
|
+
def to_der
|
|
73
|
+
if @cert.kind_of?(OpenSSL::X509::Certificate)
|
|
74
|
+
return @cert.to_der
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Returns beginning (notBefore) of certificate validity period
|
|
79
|
+
#
|
|
80
|
+
# @return [Time] time object
|
|
81
|
+
def not_before
|
|
82
|
+
@cert.not_before
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Returns the serial number of the certificate in decimal form
|
|
86
|
+
#
|
|
87
|
+
# @return [Integer]
|
|
88
|
+
def serial
|
|
89
|
+
@cert.serial.to_i
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Returns ending (notAfter) of certificate validity period
|
|
93
|
+
#
|
|
94
|
+
# @return [Time] time object
|
|
95
|
+
def not_after
|
|
96
|
+
@cert.not_after
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Returns the certificate public key
|
|
100
|
+
#
|
|
101
|
+
# @return [OpenSSL::PKey::RSA] public key object
|
|
102
|
+
def public_key
|
|
103
|
+
@cert.public_key
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# Returns the issuer
|
|
107
|
+
#
|
|
108
|
+
# @return [OpenSSL::X509::Name] issuer object. Can be parsed as string easily
|
|
109
|
+
def issuer
|
|
110
|
+
@cert.issuer
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# @return [String] The common name (CN) component of the issuer
|
|
114
|
+
def issuer_cn
|
|
115
|
+
return nil if self.issuer.nil?
|
|
116
|
+
|
|
117
|
+
self.issuer.to_a.each do |part, value, length|
|
|
118
|
+
return value if part.upcase == 'CN'
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# return nil if we didn't find a CN part
|
|
122
|
+
return nil
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# Returns the certificate fingerprint with the specified algorithm (default sha1)
|
|
126
|
+
#
|
|
127
|
+
# @param [String] algorithm Which algorithm to use for the fingerprint. See R509::MessageDigest for supported algorithm names
|
|
128
|
+
# @return [String] hex digest of the certificate
|
|
129
|
+
def fingerprint(algorithm='sha1')
|
|
130
|
+
message_digest = R509::MessageDigest.new(algorithm)
|
|
131
|
+
md = message_digest.digest
|
|
132
|
+
md.update(@cert.to_der)
|
|
133
|
+
md.to_s
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# Returns whether the current time is between the notBefore and notAfter times in
|
|
137
|
+
# the certificate.
|
|
138
|
+
#
|
|
139
|
+
# @return [Boolean]
|
|
140
|
+
def valid?
|
|
141
|
+
valid_at?(Time.now)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# Returns whether the certificate was between its notBefore and notAfter at the time provided
|
|
145
|
+
#
|
|
146
|
+
# @param [Time,Integer] time Time object or integer timestamp
|
|
147
|
+
# @return [Boolean]
|
|
148
|
+
def valid_at?(time)
|
|
149
|
+
if time.kind_of?(Integer)
|
|
150
|
+
time = Time.at(time)
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
if (self.not_after < time) or (self.not_before > time)
|
|
154
|
+
false
|
|
155
|
+
else
|
|
156
|
+
true
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# Returns the subject
|
|
161
|
+
#
|
|
162
|
+
# @return [OpenSSL::X509::Name] subject object. Can be parsed as string easily
|
|
163
|
+
def subject
|
|
164
|
+
@cert.subject
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# @return [Boolean] Boolean of whether the object contains a private key
|
|
168
|
+
def has_private_key?
|
|
169
|
+
if not @key.nil?
|
|
170
|
+
true
|
|
171
|
+
else
|
|
172
|
+
false
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# @return [Array] list of SAN DNS names
|
|
177
|
+
def san_names
|
|
178
|
+
if self.subject_alternative_name.nil?
|
|
179
|
+
return []
|
|
180
|
+
else
|
|
181
|
+
return self.subject_alternative_name.dns_names
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
# Returns the CN component, if any, of the subject
|
|
186
|
+
#
|
|
187
|
+
# @return [String]
|
|
188
|
+
def subject_cn()
|
|
189
|
+
return self.subject_component('CN')
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
# Returns subject component
|
|
193
|
+
#
|
|
194
|
+
# @return [String] value of the subject component requested
|
|
195
|
+
def subject_component short_name
|
|
196
|
+
match = @cert.subject.to_a.find { |x| x[0] == short_name }
|
|
197
|
+
return nil if match.nil?
|
|
198
|
+
return match[1]
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
# Return the CN, as well as all the subject alternative names (SANs).
|
|
202
|
+
#
|
|
203
|
+
# @return [Array] the array of names. Returns an empty array if
|
|
204
|
+
# there are no names, at all.
|
|
205
|
+
def subject_names
|
|
206
|
+
ret = []
|
|
207
|
+
ret << subject_cn unless subject_cn.nil?
|
|
208
|
+
ret.concat( self.san_names )
|
|
209
|
+
|
|
210
|
+
return ret.sort.uniq
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
# Returns whether the public key is RSA
|
|
214
|
+
#
|
|
215
|
+
# @return [Boolean] true if the public key is RSA, false otherwise
|
|
216
|
+
def rsa?
|
|
217
|
+
@cert.public_key.kind_of?(OpenSSL::PKey::RSA)
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
# Returns whether the public key is DSA
|
|
221
|
+
#
|
|
222
|
+
# @return [Boolean] true if the public key is DSA, false otherwise
|
|
223
|
+
def dsa?
|
|
224
|
+
@cert.public_key.kind_of?(OpenSSL::PKey::DSA)
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
# Returns the bit strength of the key used to create the certificate
|
|
228
|
+
#
|
|
229
|
+
# @return [Integer] integer value of bit strength
|
|
230
|
+
def bit_strength
|
|
231
|
+
if self.rsa?
|
|
232
|
+
return @cert.public_key.n.num_bits
|
|
233
|
+
elsif self.dsa?
|
|
234
|
+
return @cert.public_key.p.num_bits
|
|
235
|
+
end
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
# Returns signature algorithm
|
|
239
|
+
#
|
|
240
|
+
# @return [String] value of the signature algorithm. E.g. sha1WithRSAEncryption, sha256WithRSAEncryption, md5WithRSAEncryption
|
|
241
|
+
def signature_algorithm
|
|
242
|
+
@cert.signature_algorithm
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
# Returns key algorithm (RSA or DSA)
|
|
246
|
+
#
|
|
247
|
+
# @return [String] value of the key algorithm. RSA or DSA
|
|
248
|
+
def key_algorithm
|
|
249
|
+
if self.rsa?
|
|
250
|
+
"RSA"
|
|
251
|
+
elsif self.dsa?
|
|
252
|
+
"DSA"
|
|
253
|
+
end
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
# Writes the Cert into the PEM format
|
|
257
|
+
# @param [String, #write] filename_or_io Either a string of the path for
|
|
258
|
+
# the file that you'd like to write, or an IO-like object.
|
|
259
|
+
def write_pem(filename_or_io)
|
|
260
|
+
write_data(filename_or_io, @cert.to_pem)
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
# Writes the Cert into the DER format
|
|
264
|
+
# @param [String, #write] filename_or_io Either a string of the path for
|
|
265
|
+
# the file that you'd like to write, or an IO-like object.
|
|
266
|
+
def write_der(filename_or_io)
|
|
267
|
+
write_data(filename_or_io, @cert.to_der)
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
# Writes cert and key into PKCS12 format using OpenSSL defaults for encryption (des3)
|
|
271
|
+
# @param [String, #write] filename_or_io Either a string of the path for
|
|
272
|
+
# the file that you'd like to write, or an IO-like object.
|
|
273
|
+
# @param [String] password password
|
|
274
|
+
# @param [String] friendly_name An optional string to encode in the PKCS12 for friendlyName. defaults to "r509 pkcs12"
|
|
275
|
+
def write_pkcs12(filename_or_io,password,friendly_name='r509 pkcs12')
|
|
276
|
+
if @key.nil?
|
|
277
|
+
raise R509::R509Error, "Writing a PKCS12 requires both key and cert"
|
|
278
|
+
end
|
|
279
|
+
pkcs12 = OpenSSL::PKCS12.create(password,friendly_name,@key.key,@cert)
|
|
280
|
+
write_data(filename_or_io, pkcs12.to_der)
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
# Checks the given CRL for this certificate's serial number. Note that this does NOT
|
|
284
|
+
# check to verify that the CRL you're checking is signed by the same CA as the cert
|
|
285
|
+
# so do that check yourself
|
|
286
|
+
#
|
|
287
|
+
# @param [R509::Crl] r509_crl A CRL from the CA that issued this certificate.
|
|
288
|
+
def is_revoked_by_crl?( r509_crl )
|
|
289
|
+
return r509_crl.revoked?( self.serial )
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
# Return the certificate extensions
|
|
293
|
+
#
|
|
294
|
+
# @return [Array] an array of hashes representing the extensions in the cert
|
|
295
|
+
def extensions
|
|
296
|
+
if @extensions.nil?
|
|
297
|
+
@extensions = Hash.new
|
|
298
|
+
@cert.extensions.each { |extension|
|
|
299
|
+
hash = {'value' => extension.value, 'critical' => extension.critical?}
|
|
300
|
+
@extensions[extension.oid] = hash
|
|
301
|
+
}
|
|
302
|
+
end
|
|
303
|
+
@extensions
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
# Returns the certificate extensions as a hash of R509::Cert::Extensions
|
|
307
|
+
# specific objects.
|
|
308
|
+
#
|
|
309
|
+
# @return [Hash] A hash, in which the values are classes from the
|
|
310
|
+
# R509::Cert::Extensions module, each specific to the extension. The hash
|
|
311
|
+
# is keyed with the R509 extension class. Extensions without an R509
|
|
312
|
+
# implementation are ignored (see #get_unknown_extensions).
|
|
313
|
+
def r509_extensions
|
|
314
|
+
if @r509_extensions.nil?
|
|
315
|
+
@r509_extensions = Extensions.wrap_openssl_extensions( self.cert.extensions )
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
return @r509_extensions
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
# Returns an array of OpenSSL::X509::Extension objects representing the
|
|
322
|
+
# extensions that do not have R509 implementations.
|
|
323
|
+
#
|
|
324
|
+
# @return [Array] An array of OpenSSL::X509::Extension objects.
|
|
325
|
+
def unknown_extensions
|
|
326
|
+
return Extensions.get_unknown_extensions( self.cert.extensions )
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
#
|
|
330
|
+
# Shortcuts to extensions
|
|
331
|
+
#
|
|
332
|
+
|
|
333
|
+
# Returns this object's BasicConstraints extension as an R509 extension
|
|
334
|
+
#
|
|
335
|
+
# @return [R509::Cert::Extensions::BasicConstraints] The object, or nil
|
|
336
|
+
# if this cert does not have a BasicConstraints extension.
|
|
337
|
+
def basic_constraints
|
|
338
|
+
return r509_extensions[R509::Cert::Extensions::BasicConstraints]
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
# Returns this object's KeyUsage extension as an R509 extension
|
|
342
|
+
#
|
|
343
|
+
# @return [R509::Cert::Extensions::KeyUsage] The object, or nil
|
|
344
|
+
# if this cert does not have a KeyUsage extension.
|
|
345
|
+
def key_usage
|
|
346
|
+
return r509_extensions[R509::Cert::Extensions::KeyUsage]
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
# Returns this object's ExtendedKeyUsage extension as an R509 extension
|
|
350
|
+
#
|
|
351
|
+
# @return [R509::Cert::Extensions::ExtendedKeyUsage] The object, or nil
|
|
352
|
+
# if this cert does not have a ExtendedKeyUsage extension.
|
|
353
|
+
def extended_key_usage
|
|
354
|
+
return r509_extensions[R509::Cert::Extensions::ExtendedKeyUsage]
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
# Returns this object's SubjectKeyIdentifier extension as an R509 extension
|
|
358
|
+
#
|
|
359
|
+
# @return [R509::Cert::Extensions::SubjectKeyIdentifier] The object, or nil
|
|
360
|
+
# if this cert does not have a SubjectKeyIdentifier extension.
|
|
361
|
+
def subject_key_identifier
|
|
362
|
+
return r509_extensions[R509::Cert::Extensions::SubjectKeyIdentifier]
|
|
363
|
+
end
|
|
364
|
+
|
|
365
|
+
# Returns this object's AuthorityKeyIdentifier extension as an R509 extension
|
|
366
|
+
#
|
|
367
|
+
# @return [R509::Cert::Extensions::AuthorityKeyIdentifier] The object, or nil
|
|
368
|
+
# if this cert does not have a AuthorityKeyIdentifier extension.
|
|
369
|
+
def authority_key_identifier
|
|
370
|
+
return r509_extensions[R509::Cert::Extensions::AuthorityKeyIdentifier]
|
|
371
|
+
end
|
|
372
|
+
|
|
373
|
+
# Returns this object's SubjectAlternativeName extension as an R509 extension
|
|
374
|
+
#
|
|
375
|
+
# @return [R509::Cert::Extensions::SubjectAlternativeName] The object, or nil
|
|
376
|
+
# if this cert does not have a SubjectAlternativeName extension.
|
|
377
|
+
def subject_alternative_name
|
|
378
|
+
return r509_extensions[R509::Cert::Extensions::SubjectAlternativeName]
|
|
379
|
+
end
|
|
380
|
+
|
|
381
|
+
# Returns this object's AuthorityInfoAccess extension as an R509 extension
|
|
382
|
+
#
|
|
383
|
+
# @return [R509::Cert::Extensions::AuthorityInfoAccess] The object, or nil
|
|
384
|
+
# if this cert does not have a AuthorityInfoAccess extension.
|
|
385
|
+
def authority_info_access
|
|
386
|
+
return r509_extensions[R509::Cert::Extensions::AuthorityInfoAccess]
|
|
387
|
+
end
|
|
388
|
+
|
|
389
|
+
# Returns this object's CrlDistributionPoints extension as an R509 extension
|
|
390
|
+
#
|
|
391
|
+
# @return [R509::Cert::Extensions::CrlDistributionPoints] The object, or nil
|
|
392
|
+
# if this cert does not have a CrlDistributionPoints extension.
|
|
393
|
+
def crl_distribution_points
|
|
394
|
+
return r509_extensions[R509::Cert::Extensions::CrlDistributionPoints]
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
private
|
|
398
|
+
# This method exists only to provide a friendlier error msg if you attempt to
|
|
399
|
+
# parse a CSR as a certificate. All for Sean
|
|
400
|
+
def csr_check(cert)
|
|
401
|
+
begin
|
|
402
|
+
csr = OpenSSL::X509::Request.new cert
|
|
403
|
+
raise R509Error, 'Cert provided is actually a certificate signing request.'
|
|
404
|
+
rescue OpenSSL::X509::RequestError
|
|
405
|
+
# do nothing, it shouldn't be a CSR anyway!
|
|
406
|
+
end
|
|
407
|
+
end
|
|
408
|
+
|
|
409
|
+
def parse_certificate(cert)
|
|
410
|
+
@cert = OpenSSL::X509::Certificate.new cert
|
|
411
|
+
end
|
|
412
|
+
|
|
413
|
+
end
|
|
414
|
+
end
|