profile
viewpoint
If you are wondering where the data of this site comes from, please visit https://api.github.com/users/voltone/events. GitMemory does not store any data, but only uses NGINX to cache data for a period of time. The idea behind GitMemory is simply to give users a better reading experience.

erlef/security-wg 62

Repo for the Security Working Group

voltone/plug_signature 14

Plug for verifying request signatures according to the IETF HTTP signatures draft specification

voltone/cipher_suites 7

Select and sort the cipher suites for an Erlang/Elixir application using the widely used OpenSSL syntax.

voltone/plug_body_digest 3

Server side implementation of RFC3230 Instance Digests as a Plug

voltone/aes_crypt 1

Elixir package for reading and writing files in AES Crypt format

voltone/curve448_ex 1

Curve448 Diffie-Hellman functions in Elixir

voltone/otp 1

Erlang/OTP

voltone/bob 0

The Builder

voltone/castore 0

Up-to-date certificate store for Elixir.

voltone/cloak_ecto 0

Encrypted fields for Ecto

issue commentlau/tzdata

Dropping hackney dependency

Is this going to become a problem with Root CA file expiring at the end of the month since we can't pass hackney options down?

Should not be an issue, for two reasons:

  • Since no ssl options are being passed to Hackney, it will use its defaults which (at least with recent Hackney versions) will verify the server cert correctly before and after the DST Root CA cert expires
  • The server that Tzdata connects to does not use a Let's Encrypt certificate, so OTP's ssl should have no problem connecting to it in any case, regardless of OTP version or the client used
wojtekmach

comment created time in 5 days

issue commentvoltone/x509

Add support for additional extensions

Hmmm are you sure about the top level type being always a sequence? What I can find just always speaks about 'DER encoded'.

I thought it was a convention among standard extensions at least, but I now noticed that SubjectKeyIdentifier is defined as a plain octet string, without a sequence. So feel free to drop the sequence :)

voltone

comment created time in 11 days

issue commentvoltone/x509

Add support for additional extensions

What does {16, [{4, Value}]} actually represent? Which is the ASN.1 tag number?

This is basically a Sequence (tag value 16) with a single element of type Octet String (tag value 4). I think the top-level type should always be a sequence, even if you only want to encode a single value.

voltone

comment created time in 11 days

issue commentvoltone/x509

Add support for additional extensions

If that really works out also using the public_key API then this would be sufficient for me.

It should. Let's say you have a macro that defines the OID value as a tuple and you want to support a single binary value, you can just wrap that in an Extension record and use that alongside other extension in a Certificate or OTPCertificate record:

my_extension(Value) ->
  %% ASN.1 universal tag value 4: Octet String
  DER = asn1rt_nif:encode_ber_tlv({16, [{4, Value}]}),
  #'Extension'{extnID = ?my_extension_oid, extnValue = DER}.

Encoding non-binary values, such as integers, is a bit harder as encode_ber_tlv does not take care of the type-specific conversion.

voltone

comment created time in 11 days

issue commentvoltone/x509

Add support for additional extensions

@voltone thanks for the answer! However, I meant custom extensions, e.g. not standard extensions. I want to create my own extensions for client certificates. I'll test around throughout the week and check what's possible.

Do you basically just need an OID and a blob of DER-encoded data. You can mint your own OIDs within the enterprise namespace if you have an OUI. Producing a DER version of some data structure may require defining some ASN.1 syntax and generating the encoder and decoder functions, along with a header file for the record. Or you can cheat by using the undocumented asn1rt_nif module, e.g. to wrap an arbitrary binary:

1> Hello = <<"Hello, world!">>.                      
<<"Hello, world!">>
2> asn1rt_nif:encode_ber_tlv({16, [{131072, Hello}]}).
<<48,15,128,13,72,101,108,108,111,44,32,119,111,114,108,
  100,33>>

Unfortunately I'm developing in Erlang, so I can't use your lib at all :(.

I actually have a branch somewhere that rewrites much of the code to Erlang, with the Elixir code becoming a thin wrapper and adapter to Elixir data types (e.g. DateTime). When pulled in from a Mix project it builds everything, but from Rebar3 it builds just the Erlang core. It's not quite done yet, I need some encouragement to allocate time to finish it...

voltone

comment created time in 12 days

issue commentvoltone/x509

Add support for additional extensions

Some extensions are already decoded by Erlang's :public_key, such as those mentioned at the top of this ticket, I just haven't added convenience functions to X509.Certificate.Extension for them yet. You can still look them up and work with the Erlang record directly, e.g.:

iex(3)> aia = {1, 3, 6, 1, 5, 5, 7, 1, 1}
iex(4)> pem |> X509.Certificate.from_pem!() |> X509.Certificate.extension(aia)
{:Extension, {1, 3, 6, 1, 5, 5, 7, 1, 1}, false,
 [
   {:AccessDescription, {1, 3, 6, 1, 5, 5, 7, 48, 1},
    {:uniformResourceIdentifier, 'http://ocsp.starfieldtech.com/'}},
   {:AccessDescription, {1, 3, 6, 1, 5, 5, 7, 48, 2},
    {:uniformResourceIdentifier,
     'http://certificates.starfieldtech.com/repository/sfig2.crt'}}
 ]}

Same thing for encoding certificates with additional extensions.

Any unknown extensions are represented as DER binaries, which you can encode/decode manually with a suitable ASN.1 encoder.

Is there any particular extension you are interested in @GalaxyGorilla?

voltone

comment created time in 12 days

pull request commentelixir-mint/mint

Skip expired certs in partial chain hook

Hey @ericmj @whatyouhide, will you be publishing a new release of Mint before the end of the month, in case people need it to resolve issues as a result of the DST Root CA expiry?

voltone

comment created time in 12 days

Pull request review commentelixir-mint/mint

Skip expired certs in partial chain hook

 defmodule Mint.Core.Transport.SSL do     end   end +  defp cert_expired?({_der, cert}) do+    now = DateTime.utc_now()+    {not_before, not_after} = extract_validity(cert)++    DateTime.compare(now, not_before) == :lt or+      DateTime.compare(now, not_after) == :gt+  end++  defp extract_validity(cert) do+    {:Validity, not_before, not_after} =+      cert+      |> certificate(:tbsCertificate)+      |> tbs_certificate(:validity)++    {to_datetime!(not_before), to_datetime!(not_after)}+  end+   defp extract_public_key_info(cert) do     cert     |> certificate(:tbsCertificate)     |> tbs_certificate(:subjectPublicKeyInfo)   end +  defp to_datetime!({:utcTime, time}) do+    "20#{time}"+    |> to_datetime!()+  end++  defp to_datetime!({:generalTime, time}) do+    time+    |> to_string()+    |> to_datetime!()+  end++  defp to_datetime!(+         <<year::binary-size(4), month::binary-size(2), day::binary-size(2), hour::binary-size(2),+           minute::binary-size(2), second::binary-size(2), "Z"::binary>>+       ) do+    {:ok, datetime, _} =+      DateTime.from_iso8601("#{year}-#{month}-#{day}T#{hour}:#{minute}:#{second}Z")++    datetime

There will be in 1.13, apparently...

voltone

comment created time in 24 days

PullRequestReviewEvent

Pull request review commentelixir-mint/mint

Skip expired certs in partial chain hook

 defmodule Mint.Core.Transport.SSL do     end   end +  defp cert_expired?({_der, cert}) do+    now = DateTime.utc_now()+    {not_before, not_after} = extract_validity(cert)++    DateTime.compare(now, not_before) == :lt or+      DateTime.compare(now, not_after) == :gt+  end++  defp extract_validity(cert) do+    {:Validity, not_before, not_after} =+      cert+      |> certificate(:tbsCertificate)+      |> tbs_certificate(:validity)++    {to_datetime!(not_before), to_datetime!(not_after)}+  end+   defp extract_public_key_info(cert) do     cert     |> certificate(:tbsCertificate)     |> tbs_certificate(:subjectPublicKeyInfo)   end +  defp to_datetime!({:utcTime, time}) do+    "20#{time}"+    |> to_datetime!()+  end++  defp to_datetime!({:generalTime, time}) do+    time+    |> to_string()+    |> to_datetime!()+  end++  defp to_datetime!(+         <<year::binary-size(4), month::binary-size(2), day::binary-size(2), hour::binary-size(2),+           minute::binary-size(2), second::binary-size(2), "Z"::binary>>+       ) do+    {:ok, datetime, _} =+      DateTime.from_iso8601("#{year}-#{month}-#{day}T#{hour}:#{minute}:#{second}Z")++    datetime

No such function in DateTime, I'm afraid. Only in Date, Time and NaiveDateTime...

voltone

comment created time in 24 days

PullRequestReviewEvent

push eventvoltone/mint

Bram Verburg

commit sha 945d033b9403c3d0808b355c63362d23a43a0100

Revert use of DateTime.from_iso8601!/1

view details

push time in 24 days

push eventvoltone/mint

Bram Verburg

commit sha 656fa52d43f3e138bcfc5466c1c8c04a2e1519fe

Apply suggestions from code review Co-authored-by: Eric Meadows-Jönsson <eric.meadows.jonsson@gmail.com>

view details

push time in 24 days

pull request commentelixir-mint/mint

Skip expired certs in partial chain hook

Yes, the end-to-end tests were done manually, using my blog as the server. Testing them in CI would require a stable endpoint that presents a suitable chain, and that will continue to do so indefinitely. Most servers with a Let's Encrypt certificate would probably work, at least for the time being, however:

  1. For tests to work between now and Oct 1st, the use of faketime would be needed
  2. If faketime is used after Oct 1st, at some point the server cert will become invalid because it will have been issued in the future

How about I create a PR after Oct 1st that will check for regressions, without faketime?

voltone

comment created time in 24 days

pull request commentelixir-mint/mint

Skip expired certs in partial chain hook

Ok, additional testing with the following OTP versions was successful:

  • 23.2.7 (pre-23.3)
  • 23.3.4.5 (with alternate chain support in OTP)
  • 24.0.3 (the 24.x equivalent of 23.3.4 as tested above)
  • 24.0.4 (with alternate chain support in OTP)

Of these versions, only 23.0.3 requires the fix in this PR. The other versions do not require the fix; they were tested for regressions.

voltone

comment created time in 24 days

pull request commentelixir-mint/mint

Skip expired certs in partial chain hook

Let us know when it's ready for final review.

I suppose it is. I will run a few more manual tests like the one above on other OTP versions, just to be sure. Should be able to do that later today...

voltone

comment created time in 24 days

pull request commentelixir-mint/mint

Skip expired certs in partial chain hook

Demonstrating the fix, starting by reproducing the problem described in #327:

docker run -it --rm hexpm/elixir:1.12.2-erlang-23.3.4-ubuntu-focal-20210325                Mon Aug 30 09:07:30 2021
root@1d8f3da3f4da:/# apt update && apt install -y faketime ca-certificates git-core
[...snip...]
done.
root@1d8f3da3f4da:/# faketime '2021-10-01 09:00' iex
Erlang/OTP 23 [erts-11.2.2] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [hipe]

Interactive Elixir (1.12.2) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> Mix.install([:castore, :mint], force: true)
[...snip...]
:ok
iex(2)> isrg = File.read!("/etc/ssl/certs/ISRG_Root_X1.pem") |> :public_key.pem_decode() |> hd() |> elem(1)
<<48, 130, 5, 107, 48, 130, 3, 83, 160, 3, 2, 1, 2, 2, 17, 0, 130, 16, 207, 176,
  210, 64, 227, 89, 68, 99, 224, 187, 99, 130, 139, 0, 48, 13, 6, 9, 42, 134,
  72, 134, 247, 13, 1, 1, 11, 5, 0, 48, 79, 49, ...>>
iex(3)> dst = File.read!("/etc/ssl/certs/DST_Root_CA_X3.pem") |> :public_key.pem_decode() |> hd() |> elem(1)
<<48, 130, 3, 74, 48, 130, 2, 50, 160, 3, 2, 1, 2, 2, 16, 68, 175, 176, 128,
  214, 163, 39, 186, 137, 48, 57, 134, 46, 248, 64, 107, 48, 13, 6, 9, 42, 134,
  72, 134, 247, 13, 1, 1, 5, 5, 0, 48, 63, 49, 36, ...>>
iex(4)> Mint.HTTP.connect(:https, "blog.voltone.net", 443, transport_opts: [reuse_sessions: false, cacerts: [isrg, dst]])

09:00:47.995 [info]  TLS :client: In state :certify at ssl_handshake.erl:1878 generated CLIENT ALERT: Fatal - Certificate Expired

{:error,
 %Mint.TransportError{
   reason: {:tls_alert,
    {:certificate_expired,
     'TLS client: In state certify at ssl_handshake.erl:1878 generated CLIENT ALERT: Fatal - Certificate Expired\n'}}
 }}

Here, Erlang/OTP selects the longest chain (with DST Root CA X3 as the root) and passes it to Mint's partial_chain. Because the public key of the first certificate matches a certificate in the trust store (the DST Root CA X3 certificate itself), Mint returns it as the trusted CA. Erlang/OTP then performs path validation with the entire chain, which fails on 23.3 or later because the first certificate in the chain has expired.

In the same container, starting a new IEx session with the branch from this PR:

root@1d8f3da3f4da:/# faketime '2021-10-01 09:00' iex
Erlang/OTP 23 [erts-11.2.2] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [hipe]

Interactive Elixir (1.12.2) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> Mix.install([:castore, {:mint, git: "https://github.com/voltone/mint", branch: "partial-chain-skip-expired"}], force: true)
[...snip...]
:ok
iex(2)> isrg = File.read!("/etc/ssl/certs/ISRG_Root_X1.pem") |> :public_key.pem_decode() |> hd() |> elem(1)
<<48, 130, 5, 107, 48, 130, 3, 83, 160, 3, 2, 1, 2, 2, 17, 0, 130, 16, 207, 176,
  210, 64, 227, 89, 68, 99, 224, 187, 99, 130, 139, 0, 48, 13, 6, 9, 42, 134,
  72, 134, 247, 13, 1, 1, 11, 5, 0, 48, 79, 49, ...>>
iex(3)> dst = File.read!("/etc/ssl/certs/DST_Root_CA_X3.pem") |> :public_key.pem_decode() |> hd() |> elem(1)
<<48, 130, 3, 74, 48, 130, 2, 50, 160, 3, 2, 1, 2, 2, 16, 68, 175, 176, 128,
  214, 163, 39, 186, 137, 48, 57, 134, 46, 248, 64, 107, 48, 13, 6, 9, 42, 134,
  72, 134, 247, 13, 1, 1, 5, 5, 0, 48, 63, 49, 36, ...>>
iex(4)> Mint.HTTP.connect(:https, "blog.voltone.net", 443, transport_opts: [reuse_sessions: false, cacerts: [isrg, dst]])
{:ok,
 %Mint.HTTP1{
  # ...snip...
 }}

Now Mint skips over the expired DST Root CA X3 in the chain, and starts looking for a trusted CA from the cross-signed ISRG Root X1 CA sent by the server. Since the public key of this certificate matches the ISRG Root X1 public key in the trust store, Mint returns it as the trusted CA. This time Erlang/OTP is happy with the (shortened) chain, since all certificates are valid.

Verification still works once the DST Root CA X3 certificate is removed from the trust store:

iex(5)> Mint.HTTP.connect(:https, "blog.voltone.net", 443, transport_opts: [reuse_sessions: false, cacerts: [isrg]]) {:ok,
 %Mint.HTTP1{
  # ...snip...
 }}
voltone

comment created time in 25 days

push eventvoltone/mint

Bram Verburg

commit sha ff6ae9acfac046f4aabd9b13c930be8a87296a7e

Use public API to build DateTime

view details

push time in 25 days

PR opened elixir-mint/mint

Skip expired certs in partial chain hook

Fixes #327.

Opened as draft since I want to review the changes once more after clearing my head a bit, but it seems to work in testing...

+197 -1

0 comment

4 changed files

pr created time in a month

create barnchvoltone/mint

branch : partial-chain-skip-expired

created branch time in a month

create barnchvoltone/mint

branch : main

created branch time in a month

issue commentelixir-mint/mint

DST Root CA X3 expiration

I will try to create a PR, but unfortunately I can't promise anything at this time...

voltone

comment created time in a month

issue commentelixir-mint/castore

Prepare for DST Root CA X3 expiry

In OTP 23.3 and later, an expired root CA in the trust store causes TLS handshake failures without invoking any partial_chain handler (used by many clients, including Mint and Hackney, to support cross-signed certificates)

Turns out this is not true. Sorry for the misleading info. So this opens the door to a better workaround in Mint. See https://github.com/elixir-mint/mint/issues/327

voltone

comment created time in a month

issue openedelixir-mint/mint

DST Root CA X3 expiration

When the DST Root CA X3 certificate expires on September 30 2021, certificate verification will fail for servers presenting Let's Encrypt's default 'long' chain on some Erlang/OTP versions.

Erlang/OTP versions prior to 23.3 are not affected: as long as the (now expired) DST Root CA X3 certificate is still present in the CA trust store, it will be trusted despite the expiry; once the certificate is removed, Mint's partial chain hook will make the cross-signed version of the ISRG root CA as trusted because it has the same public key as the ISRG root CA in the trust store.

Erlang/OTP versions 23.3.4.5 and later, as well as 24.0.4 and later are not effected as they include OTP-17475, which enables handling of alternate paths (actually making Mint's partial chain hook redundant).

On Erlang/OTP 23.3 till 23.3.4.4 and 24.0 till 24.0.3, Mint will fail to establish a connection to the server with Let's Encrypt's 'long' chain when the DST Root CA X3 certificate is still present in the trust store.

I previously thought the only solution was to remove the expired CA certificate from the trust store. But it turns out it is possible to work around this in the partial chain hook: if the certificate at the start of the chain has expired, the function should just drop it and recurse on the shorter chain. The next invocation will succeed because the cross-signed version of the ISRG root CA has the same public key as the ISRG root CA certificate in the trust store, and is therefore trusted.

created time in a month

push eventvoltone/plug_body_digest

Bram Verburg

commit sha ce56ee6d5c73c74ae5e82c5e1e25ca0467e4237f

Fix build on Elixir <1.10

view details

Bram Verburg

commit sha 18dd73edf44bd3a706ec19435805f1a645569b2f

Release v0.8.0

view details

push time in a month

CommitCommentEvent

push eventvoltone/plug_body_digest

Bram Verburg

commit sha bdde4e2582caa8a92cdcff117850081b0670f01b

Release v0.8.0

view details

push time in a month

push eventvoltone/plug_body_digest

Bram Verburg

commit sha 19db7084047db3e242fc053833372876b1933a5a

Fix build on Elixir <1.10

view details

push time in a month

push eventvoltone/plug_body_digest

Bram Verburg

commit sha 811f53d2d7277dca7762b80bbd3c664058fe4bee

Fix build on Elixir <1.10

view details

push time in a month

issue commentelixir-ecto/myxql

Secure SSL defaults

Use a default cacertfile that points at the current system roots. This way it doesn't need to provided and there's no CAStore dependency or manual configuration of a path that's different on different operating systems.

Unfortunately no one has, at least until now, managed to write a reliable and portable function for selecting the system CA trust store. It is not trivial to make this work across various Linux distributions, to say nothing of Mac / Windows. This is why most BEAM applications bring their own trust store in the form of a package (castore or certifi). I personally prefer to use the system store, by injecting a platform-specific path at startup, e.g. through an environment variable.

wojtekmach

comment created time in a month