changed CHANGELOG.md
 
@@ -1,5 +1,18 @@
1
1
# Changes
2
2
3
+ ## v0.7.0
4
+
5
+ ### Enhancements
6
+
7
+ * [X509.Certificate.Template] Add OCSP responder template
8
+ * [X509.Certificate.Extension] Add support for Authority Information Access
9
+ and OCSP Nocheck extensions
10
+
11
+ ### Fixes
12
+
13
+ * [X509.RDNSequence] Handle `teletexString` encoding (7-bit only, for now)
14
+ * [X509.PrivateKey] Documentation fixes
15
+
3
16
## v0.6.0
4
17
5
18
### Enhancements
changed README.md
 
@@ -90,7 +90,7 @@ Add `x509` to your list of dependencies in `mix.exs`:
90
90
```elixir
91
91
def deps do
92
92
[
93
- {:x509, "~> 0.5.4"}
93
+ {:x509, "~> 0.7.0"}
94
94
]
95
95
end
96
96
```
changed hex_metadata.config
 
@@ -25,4 +25,4 @@
25
25
{<<"links">>,[{<<"GitHub">>,<<"https://github.com/voltone/x509">>}]}.
26
26
{<<"name">>,<<"x509">>}.
27
27
{<<"requirements">>,[]}.
28
- {<<"version">>,<<"0.6.0">>}.
28
+ {<<"version">>,<<"0.7.0">>}.
changed lib/x509/asn1.ex
 
@@ -43,6 +43,7 @@ defmodule X509.ASN1 do
43
43
extension: :Extension,
44
44
basic_constraints: :BasicConstraints,
45
45
authority_key_identifier: :AuthorityKeyIdentifier,
46
+ access_description: :AccessDescription,
46
47
47
48
# CRLs
48
49
certificate_list: :CertificateList,
changed lib/x509/certificate/extension.ex
 
@@ -17,6 +17,8 @@ defmodule X509.Certificate.Extension do
17
17
| :authority_key_identifier
18
18
| :subject_alt_name
19
19
| :crl_distribution_point
20
+ | :authority_information_access
21
+ | :ocsp_nocheck
20
22
21
23
@typedoc "Supported values in the key usage extension"
22
24
@type key_usage_value ::
 
@@ -37,6 +39,12 @@ defmodule X509.Certificate.Extension do
37
39
"""
38
40
@type san_value :: String.t() | {atom(), charlist()}
39
41
42
+ @type aia_access_method ::
43
+ :ocsp
44
+ | :ca_issuers
45
+ | :time_stamping
46
+ | :ca_repository
47
+
40
48
@doc """
41
49
The basic constraints extension identifies whether the subject of the
42
50
certificate is a CA and the maximum depth of valid certification
 
@@ -299,6 +307,90 @@ defmodule X509.Certificate.Extension do
299
307
}
300
308
end
301
309
310
+ @doc """
311
+ The authority information access extension indicates how to access
312
+ information and services for the issuer of the certificate in which the
313
+ extension appears.
314
+
315
+ Information and services may include on-line validation services and CA
316
+ policy data. This extension may be included in end entity or CA certificates.
317
+
318
+ This extension is marked as non-critical.
319
+
320
+ Example:
321
+
322
+ iex> X509.Certificate.Extension.authority_info_access(
323
+ ...> ocsp: "http://ocsp.example.net/"
324
+ ...> )
325
+ {:Extension, {1, 3, 6, 1, 5, 5, 7, 1, 1}, false,
326
+ [
327
+ {:AccessDescription, {1, 3, 6, 1, 5, 5, 7, 48, 1},
328
+ {:uniformResourceIdentifier, "http://ocsp.example.net/"}}
329
+ ]}
330
+ """
331
+ # @doc since: "0.7.0"
332
+ @spec authority_info_access([{aia_access_method(), String.t()}]) :: t()
333
+ def authority_info_access(access_methods) do
334
+ extension(
335
+ extnID: oid(:"id-pe-authorityInfoAccess"),
336
+ critical: false,
337
+ extnValue: Enum.map(access_methods, &aia_access_method/1)
338
+ )
339
+ end
340
+
341
+ defp aia_access_method({:ocsp, uri}) do
342
+ access_description(
343
+ accessMethod: oid(:"id-ad-ocsp"),
344
+ accessLocation: {:uniformResourceIdentifier, uri}
345
+ )
346
+ end
347
+
348
+ defp aia_access_method({:ca_issuers, uri}) do
349
+ access_description(
350
+ accessMethod: oid(:"id-ad-caIssuers"),
351
+ accessLocation: {:uniformResourceIdentifier, uri}
352
+ )
353
+ end
354
+
355
+ defp aia_access_method({:time_stamping, uri}) do
356
+ access_description(
357
+ accessMethod: oid(:"id-ad-timeStamping"),
358
+ accessLocation: {:uniformResourceIdentifier, uri}
359
+ )
360
+ end
361
+
362
+ defp aia_access_method({:ca_repository, uri}) do
363
+ access_description(
364
+ accessMethod: oid(:"id-ad-caRepository"),
365
+ accessLocation: {:uniformResourceIdentifier, uri}
366
+ )
367
+ end
368
+
369
+ @doc """
370
+ The OCSP Nocheck extension indicates that the OCSP client can trust this
371
+ OCSP responder certificate for the lifetime of the certificate, and no
372
+ revocation checks are needed.
373
+
374
+ This extension has no value, it acts as a flag simply by being present in a
375
+ certificate's extension list.
376
+
377
+ This extension is marked as non-critical.
378
+
379
+ Example:
380
+
381
+ iex> X509.Certificate.Extension.ocsp_nocheck()
382
+ {:Extension, {1, 3, 6, 1, 5, 5, 7, 48, 1, 5}, false, <<5, 0>>}
383
+ """
384
+ # @doc since: "0.7.0"
385
+ @spec ocsp_nocheck() :: t()
386
+ def ocsp_nocheck() do
387
+ extension(
388
+ extnID: {1, 3, 6, 1, 5, 5, 7, 48, 1, 5},
389
+ critical: false,
390
+ extnValue: <<5, 0>>
391
+ )
392
+ end
393
+
302
394
@doc """
303
395
Looks up the value of a specific extension in a list.
304
396
 
@@ -313,6 +405,8 @@ defmodule X509.Certificate.Extension do
313
405
def find(list, :authority_key_identifier), do: find(list, oid(:"id-ce-authorityKeyIdentifier"))
314
406
def find(list, :subject_alt_name), do: find(list, oid(:"id-ce-subjectAltName"))
315
407
def find(list, :crl_distribution_points), do: find(list, oid(:"id-ce-cRLDistributionPoints"))
408
+ def find(list, :authority_info_access), do: find(list, oid(:"id-pe-authorityInfoAccess"))
409
+ def find(list, :ocsp_nocheck), do: find(list, {1, 3, 6, 1, 5, 5, 7, 48, 1, 5})
316
410
317
411
def find(list, extension_oid) do
318
412
Enum.find(list, &match?(extension(extnID: ^extension_oid), &1))
changed lib/x509/certificate/template.ex
 
@@ -55,6 +55,20 @@ defmodule X509.Certificate.Template do
55
55
56
56
The default validity is 1 year, plus a 30 day grace period.
57
57
58
+ * `:ocsp_responder` - designated responder to sign OCSP responses on behalf
59
+ of the issuing CA.
60
+
61
+ The Extended Key Usage extension is set to allow OCSP signing only. Must
62
+ be issued directly from the CA certificate for which OCSP responses will
63
+ be signed.
64
+
65
+ The OCSP Nocheck extension is included, to disable revocation checks for
66
+ the OCSP responder certificate. To exclude this extension override it
67
+ with a value of `false` (e.g. `extensions: [ocsp_nocheck: false]`)
68
+
69
+ The default validity is just 30 days, due to the fact that revocation
70
+ is not possible when OCSP Nocheck is set.
71
+
58
72
All of the above templates generate a random 8 byte (64 bit) serial number,
59
73
which can be overriden through the `:serial` option (see below).
60
74
 
@@ -165,6 +179,23 @@ defmodule X509.Certificate.Template do
165
179
|> new(opts)
166
180
end
167
181
182
+ def new(:ocsp_responder, opts) do
183
+ %__MODULE__{
184
+ # 30 days
185
+ validity: 30,
186
+ hash: :sha256,
187
+ extensions: [
188
+ basic_constraints: basic_constraints(false),
189
+ key_usage: key_usage([:digitalSignature]),
190
+ ext_key_usage: ext_key_usage([:OCSPSigning]),
191
+ subject_key_identifier: true,
192
+ authority_key_identifier: true,
193
+ ocsp_nocheck: ocsp_nocheck()
194
+ ]
195
+ }
196
+ |> new(opts)
197
+ end
198
+
168
199
def new(template, opts) do
169
200
override =
170
201
opts
changed lib/x509/private_key.ex
 
@@ -37,7 +37,7 @@ defmodule X509.PrivateKey do
37
37
@default_e 65537
38
38
39
39
@doc """
40
- Generates a new private RSA private key. To derive the public key, use
40
+ Generates a new RSA private key. To derive the public key, use
41
41
`X509.PublicKey.derive/1`.
42
42
43
43
The key length in bits must be specified as an integer (minimum 256 bits).
 
@@ -52,10 +52,10 @@ defmodule X509.PrivateKey do
52
52
end
53
53
54
54
@doc """
55
- Generates a new private EC private key. To derive the public key, use
55
+ Generates a new EC private key. To derive the public key, use
56
56
`X509.PublicKey.derive/1`.
57
57
58
- The second parameter must specify a named curve. The curve can be specified
58
+ The first parameter must specify a named curve. The curve can be specified
59
59
as an atom or an OID tuple.
60
60
61
61
Note that this function uses Erlang/OTP's `:public_key` application, which
changed lib/x509/rdn_sequence.ex
 
@@ -280,6 +280,8 @@ defmodule X509.RDNSequence do
280
280
defp attr_value_to_string({:utf8String, value}), do: value
281
281
defp attr_value_to_string({:printableString, value}), do: List.to_string(value)
282
282
defp attr_value_to_string({:ia5String, value}), do: List.to_string(value)
283
+ # FIXME: for 8-bit teletexString this requires mapping (see RFC1345)
284
+ defp attr_value_to_string({:teletexString, value}), do: List.to_string(value)
283
285
defp attr_value_to_string(value), do: List.to_string(value)
284
286
285
287
# Splits an attribute in the form of "type=value" into a {type, value} tuple
changed mix.exs
 
@@ -1,7 +1,7 @@
1
1
defmodule X509.MixProject do
2
2
use Mix.Project
3
3
4
- @version "0.6.0"
4
+ @version "0.7.0"
5
5
6
6
def project do
7
7
[