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.
Files changed (162) hide show
  1. data/README.md +447 -0
  2. data/Rakefile +38 -0
  3. data/bin/r509 +96 -0
  4. data/bin/r509-parse +35 -0
  5. data/doc/R509.html +154 -0
  6. data/doc/R509/Cert.html +3954 -0
  7. data/doc/R509/Cert/Extensions.html +360 -0
  8. data/doc/R509/Cert/Extensions/AuthorityInfoAccess.html +391 -0
  9. data/doc/R509/Cert/Extensions/AuthorityKeyIdentifier.html +148 -0
  10. data/doc/R509/Cert/Extensions/BasicConstraints.html +482 -0
  11. data/doc/R509/Cert/Extensions/CrlDistributionPoints.html +316 -0
  12. data/doc/R509/Cert/Extensions/ExtendedKeyUsage.html +780 -0
  13. data/doc/R509/Cert/Extensions/KeyUsage.html +1230 -0
  14. data/doc/R509/Cert/Extensions/SubjectAlternativeName.html +467 -0
  15. data/doc/R509/Cert/Extensions/SubjectKeyIdentifier.html +216 -0
  16. data/doc/R509/CertificateAuthority.html +126 -0
  17. data/doc/R509/CertificateAuthority/Signer.html +855 -0
  18. data/doc/R509/Config.html +127 -0
  19. data/doc/R509/Config/CaConfig.html +2144 -0
  20. data/doc/R509/Config/CaConfigPool.html +599 -0
  21. data/doc/R509/Config/CaProfile.html +656 -0
  22. data/doc/R509/Config/SubjectItemPolicy.html +578 -0
  23. data/doc/R509/Crl.html +126 -0
  24. data/doc/R509/Crl/Administrator.html +2077 -0
  25. data/doc/R509/Crl/Parser.html +1224 -0
  26. data/doc/R509/Csr.html +2248 -0
  27. data/doc/R509/IOHelpers.html +564 -0
  28. data/doc/R509/MessageDigest.html +396 -0
  29. data/doc/R509/NameSanitizer.html +319 -0
  30. data/doc/R509/Ocsp.html +128 -0
  31. data/doc/R509/Ocsp/Request.html +126 -0
  32. data/doc/R509/Ocsp/Request/Nonce.html +160 -0
  33. data/doc/R509/Ocsp/Response.html +837 -0
  34. data/doc/R509/OidMapper.html +393 -0
  35. data/doc/R509/PrivateKey.html +1647 -0
  36. data/doc/R509/R509Error.html +134 -0
  37. data/doc/R509/Spki.html +1424 -0
  38. data/doc/R509/Subject.html +836 -0
  39. data/doc/R509/Validity.html +160 -0
  40. data/doc/R509/Validity/Checker.html +320 -0
  41. data/doc/R509/Validity/DefaultChecker.html +283 -0
  42. data/doc/R509/Validity/DefaultWriter.html +330 -0
  43. data/doc/R509/Validity/Status.html +561 -0
  44. data/doc/R509/Validity/Writer.html +394 -0
  45. data/doc/_index.html +501 -0
  46. data/doc/class_list.html +53 -0
  47. data/doc/css/common.css +1 -0
  48. data/doc/css/full_list.css +57 -0
  49. data/doc/css/style.css +328 -0
  50. data/doc/file.README.html +534 -0
  51. data/doc/file.r509.html +149 -0
  52. data/doc/file_list.html +58 -0
  53. data/doc/frames.html +28 -0
  54. data/doc/index.html +534 -0
  55. data/doc/js/app.js +208 -0
  56. data/doc/js/full_list.js +173 -0
  57. data/doc/js/jquery.js +4 -0
  58. data/doc/methods_list.html +1932 -0
  59. data/doc/top-level-namespace.html +112 -0
  60. data/lib/r509.rb +22 -0
  61. data/lib/r509/cert.rb +414 -0
  62. data/lib/r509/cert/extensions.rb +309 -0
  63. data/lib/r509/certificateauthority.rb +290 -0
  64. data/lib/r509/config.rb +407 -0
  65. data/lib/r509/crl.rb +379 -0
  66. data/lib/r509/csr.rb +324 -0
  67. data/lib/r509/exceptions.rb +5 -0
  68. data/lib/r509/io_helpers.rb +52 -0
  69. data/lib/r509/messagedigest.rb +49 -0
  70. data/lib/r509/ocsp.rb +85 -0
  71. data/lib/r509/oidmapper.rb +32 -0
  72. data/lib/r509/privatekey.rb +185 -0
  73. data/lib/r509/spki.rb +112 -0
  74. data/lib/r509/subject.rb +133 -0
  75. data/lib/r509/validity.rb +92 -0
  76. data/lib/r509/version.rb +4 -0
  77. data/r509.yaml +73 -0
  78. data/spec/cert/extensions_spec.rb +632 -0
  79. data/spec/cert_spec.rb +321 -0
  80. data/spec/certificate_authority_spec.rb +260 -0
  81. data/spec/config_spec.rb +349 -0
  82. data/spec/crl_spec.rb +215 -0
  83. data/spec/csr_spec.rb +302 -0
  84. data/spec/fixtures.rb +233 -0
  85. data/spec/fixtures/cert1.der +0 -0
  86. data/spec/fixtures/cert1.pem +24 -0
  87. data/spec/fixtures/cert1_public_key_modulus.txt +1 -0
  88. data/spec/fixtures/cert3.p12 +0 -0
  89. data/spec/fixtures/cert3.pem +28 -0
  90. data/spec/fixtures/cert3_key.pem +27 -0
  91. data/spec/fixtures/cert3_key_des3.pem +30 -0
  92. data/spec/fixtures/cert4.pem +14 -0
  93. data/spec/fixtures/cert5.pem +30 -0
  94. data/spec/fixtures/cert6.pem +26 -0
  95. data/spec/fixtures/cert_expired.pem +26 -0
  96. data/spec/fixtures/cert_not_yet_valid.pem +26 -0
  97. data/spec/fixtures/cert_san.pem +27 -0
  98. data/spec/fixtures/cert_san2.pem +22 -0
  99. data/spec/fixtures/config_pool_test_minimal.yaml +15 -0
  100. data/spec/fixtures/config_test.yaml +41 -0
  101. data/spec/fixtures/config_test_engine_key.yaml +7 -0
  102. data/spec/fixtures/config_test_engine_no_key_name.yaml +6 -0
  103. data/spec/fixtures/config_test_minimal.yaml +7 -0
  104. data/spec/fixtures/config_test_password.yaml +7 -0
  105. data/spec/fixtures/config_test_various.yaml +100 -0
  106. data/spec/fixtures/crl_list_file.txt +1 -0
  107. data/spec/fixtures/crl_with_reason.pem +17 -0
  108. data/spec/fixtures/csr1.der +0 -0
  109. data/spec/fixtures/csr1.pem +17 -0
  110. data/spec/fixtures/csr1_key.der +0 -0
  111. data/spec/fixtures/csr1_key.pem +27 -0
  112. data/spec/fixtures/csr1_key_encrypted_des3.pem +30 -0
  113. data/spec/fixtures/csr1_newlines.pem +32 -0
  114. data/spec/fixtures/csr1_no_begin_end.pem +15 -0
  115. data/spec/fixtures/csr1_public_key_modulus.txt +1 -0
  116. data/spec/fixtures/csr2.pem +15 -0
  117. data/spec/fixtures/csr2_key.pem +27 -0
  118. data/spec/fixtures/csr3.pem +16 -0
  119. data/spec/fixtures/csr4.pem +25 -0
  120. data/spec/fixtures/csr_dsa.pem +15 -0
  121. data/spec/fixtures/csr_invalid_signature.pem +13 -0
  122. data/spec/fixtures/dsa_key.pem +20 -0
  123. data/spec/fixtures/key4.pem +27 -0
  124. data/spec/fixtures/key4_encrypted_des3.pem +30 -0
  125. data/spec/fixtures/missing_key_identifier_ca.cer +21 -0
  126. data/spec/fixtures/missing_key_identifier_ca.key +27 -0
  127. data/spec/fixtures/ocsptest.r509.local.pem +27 -0
  128. data/spec/fixtures/ocsptest.r509.local_ocsp_request.der +0 -0
  129. data/spec/fixtures/ocsptest2.r509.local.pem +27 -0
  130. data/spec/fixtures/second_ca.cer +26 -0
  131. data/spec/fixtures/second_ca.key +27 -0
  132. data/spec/fixtures/spkac.der +0 -0
  133. data/spec/fixtures/spkac.txt +1 -0
  134. data/spec/fixtures/spkac_dsa.txt +1 -0
  135. data/spec/fixtures/stca.pem +22 -0
  136. data/spec/fixtures/stca_ocsp_request.der +0 -0
  137. data/spec/fixtures/stca_ocsp_response.der +0 -0
  138. data/spec/fixtures/test1.csr +17 -0
  139. data/spec/fixtures/test_ca.cer +22 -0
  140. data/spec/fixtures/test_ca.key +28 -0
  141. data/spec/fixtures/test_ca.p12 +0 -0
  142. data/spec/fixtures/test_ca_des3.key +30 -0
  143. data/spec/fixtures/test_ca_ocsp.cer +26 -0
  144. data/spec/fixtures/test_ca_ocsp.key +27 -0
  145. data/spec/fixtures/test_ca_ocsp.p12 +0 -0
  146. data/spec/fixtures/test_ca_ocsp_chain.txt +48 -0
  147. data/spec/fixtures/test_ca_ocsp_response.der +0 -0
  148. data/spec/fixtures/test_ca_subroot.cer +26 -0
  149. data/spec/fixtures/test_ca_subroot.key +27 -0
  150. data/spec/fixtures/test_ca_subroot_ocsp.cer +25 -0
  151. data/spec/fixtures/test_ca_subroot_ocsp.key +27 -0
  152. data/spec/fixtures/test_ca_subroot_ocsp_response.der +0 -0
  153. data/spec/fixtures/unknown_oid.csr +17 -0
  154. data/spec/message_digest_spec.rb +89 -0
  155. data/spec/ocsp_spec.rb +111 -0
  156. data/spec/oid_mapper_spec.rb +31 -0
  157. data/spec/privatekey_spec.rb +198 -0
  158. data/spec/spec_helper.rb +14 -0
  159. data/spec/spki_spec.rb +157 -0
  160. data/spec/subject_spec.rb +203 -0
  161. data/spec/validity_spec.rb +98 -0
  162. 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
+ &mdash; 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> &raquo;
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