From b8f5bec0237f0cb9d14abe78671ad3c54ce70a92 Mon Sep 17 00:00:00 2001 From: Pete Kazmier Date: Sun, 30 Jun 2024 10:43:18 -0400 Subject: [PATCH 1/4] fix: be explicit with attribute order in aggregrate It was by pure chance the tests passed before as maps are unordered, so iterating over the map to create the aggregate string will vary. This change makes the order of the aggregated string fixed. I used the same order that was expected in the tests. --- lib/easy_ssl.ex | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/lib/easy_ssl.ex b/lib/easy_ssl.ex index a474872..3d02950 100644 --- a/lib/easy_ssl.ex +++ b/lib/easy_ssl.ex @@ -334,14 +334,11 @@ defmodule EasySSL do end defp aggregate_rdnsequence(rdnsequence) do - rdnsequence - # Filter out empty values - |> Enum.filter(fn {_, v} -> v != nil end) - # Turn everything in to a string so C=blah.com - |> Enum.map(fn {k, v} -> (k |> to_string) <> "=" <> (v |> to_string) end) - # Add a buffer to the front to - |> Enum.join("/") - |> String.replace_prefix("", "/") + [ :C, :CN, :L, :O, :OU, :ST, :emailAddress ] + |> Enum.filter(& rdnsequence[&1] != nil) + |> Enum.map(fn k -> (k |> to_string) <> "=" <> (rdnsequence[k] |> to_string) end) + |> Enum.join("/") + |> String.replace_prefix("", "/") end defp parse_extensions(cert) do From fcf13cfd39de68f5b61522142f8079b9adfd87c7 Mon Sep 17 00:00:00 2001 From: Pete Kazmier Date: Sun, 30 Jun 2024 19:21:10 -0400 Subject: [PATCH 2/4] feat: add support for multi-value attributes Fully backwards compatible feature enhancement. The RDN sequence for both subject and issuer is allowed to contain the same attribute more than once. For example, Entrust certificates have two OU attributes. Passing the new `multivalue: true` option to either of the parse functions yields this output, where values for the subject and issuer are now lists. In the example below, you can see both of the OU values. Further, the aggregated string also includes both now. %{ aggregated: "/C=US/CN=Entrust Certification Authority - L1K/O=Entrust, Inc./OU=See www.entrust.net/legal-terms, (c) 2012 Entrust, Inc. - for authorized use only", CN: ["Entrust Certification Authority - L1K"], C: ["US"], L: [], ST: [], O: ["Entrust, Inc."], OU: ["See www.entrust.net/legal-terms", "(c) 2012 Entrust, Inc. - for authorized use only"], emailAddress: [] } Without the `multivalue` option, it parses is it did prior to this change dropping all but the last of the duplicated attributes, which is broken technically. In the spirit of backwards compatibility, however, it parses the same as before: %{ aggregated: "/C=US/CN=Entrust Certification Authority - L1K/O=Entrust, Inc./OU=(c) 2012 Entrust, Inc. - for authorized use only", emailAddress: nil, CN: "Entrust Certification Authority - L1K", OU: "(c) 2012 Entrust, Inc. - for authorized use only", O: "Entrust, Inc.", ST: nil, L: nil, C: "US" } --- README.md | 45 ++++++++++ lib/easy_ssl.ex | 145 ++++++++++++++++++++++++++++----- test/data/der/www.espn.com.der | Bin 0 -> 2816 bytes test/easy_ssl_test.exs | 56 +++++++++++++ 4 files changed, 227 insertions(+), 19 deletions(-) create mode 100644 test/data/der/www.espn.com.der diff --git a/README.md b/README.md index d347465..7b53011 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,51 @@ We aim to make the usage as stupid simple as possible, so there are only 2 expor } ``` +If you want support for multi-value attributes in the subject and issuer, pass +the `multivalue: true` option to the parse functions. Doing so will yield this +output where lists are used as values for the attributes. + +```elixir +%{ + extensions: %{ + authorityInfoAccess: "CA Issuers - URI:http://certificates.godaddy.com/repository/gd_intermediate.crt\nOCSP - URI:http://ocsp.godaddy.com/\n", + authorityKeyIdentifier: "keyid:FD:AC:61:32:93:6C:45:D6:E2:EE:85:5F:9A:BA:E7:76:99:68:CC:E7\n", + basicConstraints: "CA:FALSE", + certificatePolicies: "Policy: 2.16.840.1.114413.1.7.23.1\n CPS: http://certificates.godaddy.com/repository/", + crlDistributionPoints: "Full Name:\n URI:http://crl.godaddy.com/gds1-90.crl", + extendedKeyUsage: "TLS Web server authentication, TLS Web client authentication", + keyUsage: "Digital Signature, Key Encipherment", + subjectAltName: "DNS:acaline.com, DNS:www.acaline.com", + subjectKeyIdentifier: "E6:61:14:4E:5A:4B:51:0C:4E:6C:5E:3C:79:61:65:D4:BD:64:94:BE" + }, + fingerprint: "FA:BE:B5:9B:ED:C2:2B:42:7E:B1:45:C8:9A:8A:73:16:4A:A0:10:09", + issuer: %{ + C: ["US"], + CN: ["Go Daddy Secure Certification Authority"], + L: ["Scottsdale"], + O: ["GoDaddy.com, Inc."], + OU: ["http://certificates.godaddy.com/repository"], + ST: ["Arizona"], + aggregated: "/C=US/CN=Go Daddy Secure Certification Authority/L=Scottsdale/O=GoDaddy.com, Inc./OU=http://certificates.godaddy.com/repository/ST=Arizona", + emailAddress: [] + }, + not_after: 1398523877, + not_before: 1366987877, + serial_number: "27ACAE30B9F323", + signature_algorithm: "sha, rsa", + subject: %{ + C: [], + CN: ["www.acaline.com"], + L: [], + O: [], + OU: ["Domain Control Validated"], + ST: [], + aggregated: "/CN=www.acaline.com/OU=Domain Control Validated", + emailAddress: [] + } +} +``` + ### parse_der Parses a DER-encoded X509 certificate diff --git a/lib/easy_ssl.ex b/lib/easy_ssl.ex index 3d02950..71e58c2 100644 --- a/lib/easy_ssl.ex +++ b/lib/easy_ssl.ex @@ -68,22 +68,65 @@ defmodule EasySSL do OU: "Domain Control Validated", ST: nil, aggregated: "/CN=www.acaline.com/OU=Domain Control Validated", - emailAddress: nil + emailAddress: [] + } + } + + # Pass in a binary (from Base.decode64, or some other source) and parse + # with multivalues as part of subject and issuer attributes. + iex(1)> EasySSL.parse_der(<<...>>, multivalue: true) + %{ + extensions: %{ + authorityInfoAccess: "CA Issuers - URI:http://certificates.godaddy.com/repository/gd_intermediate.crt\\nOCSP - URI:http://ocsp.godaddy.com/\\n", + authorityKeyIdentifier: "keyid:FD:AC:61:32:93:6C:45:D6:E2:EE:85:5F:9A:BA:E7:76:99:68:CC:E7\\n", + basicConstraints: "CA:FALSE", + certificatePolicies: "Policy: 2.16.840.1.114413.1.7.23.1\\n CPS: http://certificates.godaddy.com/repository/", + crlDistributionPoints: "Full Name:\\n URI:http://crl.godaddy.com/gds1-90.crl", + extendedKeyUsage: "TLS Web server authentication, TLS Web client authentication", + keyUsage: "Digital Signature, Key Encipherment", + subjectAltName: "DNS:acaline.com, DNS:www.acaline.com", + subjectKeyIdentifier: "E6:61:14:4E:5A:4B:51:0C:4E:6C:5E:3C:79:61:65:D4:BD:64:94:BE" + }, + fingerprint: "FA:BE:B5:9B:ED:C2:2B:42:7E:B1:45:C8:9A:8A:73:16:4A:A0:10:09", + issuer: %{ + C: ["US"], + CN: ["Go Daddy Secure Certification Authority"], + L: ["Scottsdale"], + O: ["GoDaddy.com, Inc."], + OU: ["http://certificates.godaddy.com/repository"], + ST: ["Arizona"], + aggregated: "/C=US/CN=Go Daddy Secure Certification Authority/L=Scottsdale/O=GoDaddy.com, Inc./OU=http://certificates.godaddy.com/repository/ST=Arizona", + emailAddress: [] + }, + not_after: 1398523877, + not_before: 1366987877, + serial_number: "27ACAE30B9F323", + signature_algorithm: "sha, rsa", + subject: %{ + C: [], + CN: ["www.acaline.com"], + L: [], + O: [], + OU: ["Domain Control Validated"], + ST: [], + aggregated: "/CN=www.acaline.com/OU=Domain Control Validated", + emailAddress: [] } } """ - def parse_der(certificate_der, opts \\ [all_domains: false, serialize: false]) when is_binary(certificate_der) do + def parse_der(certificate_der, opts \\ [all_domains: false, serialize: false, multivalue: false]) when is_binary(certificate_der) do cert = :public_key.pkix_decode_cert(certificate_der, :otp) |> get_field(:tbsCertificate) serialized_certificate = %{} |> Map.put(:fingerprint, certificate_der |> fingerprint_cert) |> Map.put(:serial_number, cert |> get_field(:serialNumber) |> Integer.to_string(16)) |> Map.put(:signature_algorithm, cert |> parse_signature_algo) - |> Map.put(:subject, cert |> parse_rdnsequence(:subject)) - |> Map.put(:issuer, cert |> parse_rdnsequence(:issuer)) + |> Map.put(:subject, cert |> parse_rdnsequence(:subject, multivalue: opts[:multivalue])) + |> Map.put(:issuer, cert |> parse_rdnsequence(:issuer, multivalue: opts[:multivalue])) |> Map.put(:extensions, cert |> parse_extensions) |> Map.merge(parse_expiry(cert)) + Enum.reduce(opts, serialized_certificate, fn {option, flag}, serialized_certificate -> case option do :all_domains when flag == true -> @@ -93,6 +136,7 @@ defmodule EasySSL do :serialize when flag == true -> serialized_certificate |> Map.put(:as_der, Base.encode64(certificate_der)) + _ -> serialized_certificate end end) @@ -168,12 +212,54 @@ defmodule EasySSL do OU: "Domain Control Validated", ST: nil, aggregated: "/CN=www.acaline.com/OU=Domain Control Validated", - emailAddress: nil + emailAddress: [] + } + } + + # Pass in a binary (from Base.decode64, or some other source) and parse + # with multivalues as part of subject and issuer attributes. + iex(1)> EasySSL.parse_pem("-----BEGIN CERTIFICATE-----\\nMII...", multivalue: true) + %{ + extensions: %{ + authorityInfoAccess: "CA Issuers - URI:http://certificates.godaddy.com/repository/gd_intermediate.crt\\nOCSP - URI:http://ocsp.godaddy.com/\\n", + authorityKeyIdentifier: "keyid:FD:AC:61:32:93:6C:45:D6:E2:EE:85:5F:9A:BA:E7:76:99:68:CC:E7\\n", + basicConstraints: "CA:FALSE", + certificatePolicies: "Policy: 2.16.840.1.114413.1.7.23.1\\n CPS: http://certificates.godaddy.com/repository/", + crlDistributionPoints: "Full Name:\\n URI:http://crl.godaddy.com/gds1-90.crl", + extendedKeyUsage: "TLS Web server authentication, TLS Web client authentication", + keyUsage: "Digital Signature, Key Encipherment", + subjectAltName: "DNS:acaline.com, DNS:www.acaline.com", + subjectKeyIdentifier: "E6:61:14:4E:5A:4B:51:0C:4E:6C:5E:3C:79:61:65:D4:BD:64:94:BE" + }, + fingerprint: "FA:BE:B5:9B:ED:C2:2B:42:7E:B1:45:C8:9A:8A:73:16:4A:A0:10:09", + issuer: %{ + C: ["US"], + CN: ["Go Daddy Secure Certification Authority"], + L: ["Scottsdale"], + O: ["GoDaddy.com, Inc."], + OU: ["http://certificates.godaddy.com/repository"], + ST: ["Arizona"], + aggregated: "/C=US/CN=Go Daddy Secure Certification Authority/L=Scottsdale/O=GoDaddy.com, Inc./OU=http://certificates.godaddy.com/repository/ST=Arizona", + emailAddress: [] + }, + not_after: 1398523877, + not_before: 1366987877, + serial_number: "27ACAE30B9F323", + signature_algorithm: "sha, rsa", + subject: %{ + C: [], + CN: ["www.acaline.com"], + L: [], + O: [], + OU: ["Domain Control Validated"], + ST: [], + aggregated: "/CN=www.acaline.com/OU=Domain Control Validated", + emailAddress: [] } } """ def parse_pem(cert_charlist) when is_list(cert_charlist) do parse_pem(cert_charlist |> to_string) end - def parse_pem(cert_pem, opts \\ [all_domains: false, return_base64: false]) do + def parse_pem(cert_pem, opts \\ [all_domains: false, return_base64: false, multivalue: false]) do cert_regex = ~r/^\-{5}BEGIN\sCERTIFICATE\-{5}\n(?[^\-]+)\-{5}END\sCERTIFICATE\-{5}/ match = Regex.named_captures(cert_regex, cert_pem) @@ -276,15 +362,15 @@ defmodule EasySSL do |> Enum.join(", ") end - defp parse_rdnsequence(cert, field) do + defp parse_rdnsequence(cert, field, opts) do rdnsequence = %{ - :CN => nil, - :C => nil, - :L => nil, - :ST => nil, - :O => nil, - :OU => nil, - :emailAddress => nil + :CN => [], + :C => [], + :L => [], + :ST => [], + :O => [], + :OU => [], + :emailAddress => [] } {:rdnSequence, rdnsequence_attribute} = cert |> get_field(field) @@ -304,13 +390,34 @@ defmodule EasySSL do end case attr_atom do - nil -> rdnsequence - _ -> %{rdnsequence | attr_atom => attribute_value |> coerce_to_string |> to_string} + nil -> + rdnsequence + _ -> + attribute_value = attribute_value |> coerce_to_string |> to_string + new_attribute_values = [ attribute_value | rdnsequence[attr_atom] ] + %{rdnsequence | attr_atom => new_attribute_values} end end) - Map.put(rdnsequence, :aggregated, rdnsequence |> aggregate_rdnsequence) + case opts[:multivalue] do + true -> + # Reverse order of multi attribute values to honor order in cert + rdnsequence = Map.new(rdnsequence, fn {k, v} -> {k, Enum.reverse(v)} end) + Map.put(rdnsequence, :aggregated, rdnsequence |> aggregate_rdnsequence) + _ -> + # Save only the last value, then aggregate into a string + aggregated = Map.new(rdnsequence, fn + {k, [h|_]} -> {k, [h]} + {k, []} -> {k, []} + end) |> aggregate_rdnsequence + + # Change list values to single elements, then add aggregated string + Map.new(rdnsequence, fn + {k, [h|_]} -> {k, h} + {k, []} -> {k, nil} + end) |> Map.put(:aggregated, aggregated) + end end defp parse_crl_distribution_points(crl_distribution_points) @@ -335,8 +442,8 @@ defmodule EasySSL do defp aggregate_rdnsequence(rdnsequence) do [ :C, :CN, :L, :O, :OU, :ST, :emailAddress ] - |> Enum.filter(& rdnsequence[&1] != nil) - |> Enum.map(fn k -> (k |> to_string) <> "=" <> (rdnsequence[k] |> to_string) end) + |> Enum.filter(& !Enum.empty?(rdnsequence[&1])) + |> Enum.map(fn k -> (k |> to_string) <> "=" <> (rdnsequence[k] |> Enum.join(", ")) end) |> Enum.join("/") |> String.replace_prefix("", "/") end diff --git a/test/data/der/www.espn.com.der b/test/data/der/www.espn.com.der new file mode 100644 index 0000000000000000000000000000000000000000..f462d4fb9e414eaec46322653d1e166819d31d91 GIT binary patch literal 2816 zcmaJ@c~}!?8lOpq071@#%LojF`-oqVtGLx#ITeL+tQM#`OvVrhNt{eTv;xjn#9BpU zw>*L(6^df(b}hRr<#EM|N4HjyLu^?PYf<|MEm{v`sj`z0j*xc$$n(tizQ5ml{PKPW zpt-*S+I*;v&4O7hn}t5dH*^<#-#5`06E_Udo4}G|?q3>LI%WyO7A6qb*($aG<{Wk! z!r`&fQp65`uU&9?meC4|)TpUIG+u#=#J<2=Yq#LJr4R&KP*5Nuru-rWK`oXOQcNC1 z5oDfP{2BISL7ri6JYcI0 zZ^q-U#N;xj2!#w2+W;%A(UfQUriRSI6uDv)xN0q2o?~h@fv&^k6dEN{D~LjLr7};2 zDGJ5*fHzg=0-X?Ql|qCo^8gKd%#{~5f!H)`4Ka2ui-uw7v$2?asV^NR*UOd7&88F0 ziGnM2seZzdnAWBBMPs}8LsudcO*u~AI>i)K-h0Y_P`)C0KR6&5{K}-^1<`e?I(0O# zKKx++-LHVl&N~y&?pCp`{jK3=y9x*I=2yK3>MVOR25;<&%sO-T4{xQc$|KvdYR`7I ztZG_j9@uf>Nq*Ew$Az5RQVXH?`6JKQ+FAXj&3emK{)@bC;i3x9ssVZ6H`}+jF6wgn zjJq%5Q2YIySLsjVeY=lbwhgH1_Y%~+Gx<|H(N~ew-6DPyoJk8=-T(HDj2vY`$(s7= zRy#q4$AulYkG>e)-$^xxz3eY>4suT@tJ-+!Kj+5VzCXI=_Q9ye9V|8s!S%Fh9H333 zzyd}>7aj~xA}jy_7wyUlaX|Rc8qasUlg7p~doGg?Qyo)5_hd3~)4GL-6L2Wu)5lcQ zz}b}L9ou`xt`#5ObeWsb2C_M30UX%G#1w{+Opp$Q(`x{iI%ZRpDsu5+C9YP@9b2$u z2E;1$(StAI5bRz6C^`oN^wI1fj{uA^RDwO_0ThMQf|m3@(G45 zV(frM_G)Ri2#wIpqKGz_9NNlXgsEgALO)3~&z~76k}x!K{bvEw-^}KtEvM|bL^p-B zoxf-^rZA-P4Q*R6?Yz?V{vs7dQVN1pX|iTxGhj8dH7PZvWaOGI$&1;8gj7iuYN;xv zTBhBRA~iwg%Wz^A7W98%Dw4>T5zN^!9o1~+OTeh5pwzm$jbL_jJJMJ0sI?iWq<8RD zIIasLA@XN4@usZ|Y9^^WNvJ7OhHHEIoz#3a(;rn_Bu}ik!475SF5yY<4pSm`P=<_89=7RFp|l&0Hg5iAZ?KGEyFGN5v)d2WW!+0(c>8n>)}G{-6<>=YB`Li$M9%T1~xA zX0=UwM25U)aC!2u%cDE{1^Z;@PybhPI;;A%L4D%Ky2P;{nu&VC^^*M`yPQHs##}6& z?=>fj|Jm$t(f$3u-u^q>`zSa*l!dO|8+WSjlej0176170$I8~%$4wisZS1P`k*^|J zRvo_i`P|nA^O$2^8!*&zbJ5nT4_8)Y+!1=-t6g`47|>EU z@H66Z?W4h8*5{^glq{_od)WP~ZK&;ei^oW5MD#_$xJ}=&$)}C`p4mJ5Iqa#SAAiFM z#8{>4CTzBH>^d_}J&2!>_)!~@G`|qYL8yO6yOVj@#!AIok?QkpdwR+fOZfQC*e8c2 zytJ~I=tI`N;T_>$7ur6q8%=R|^!hq+HT&RX;}M_o(?ydR(D2a04ehY?=b`RaX~Jv8 W+cMkEuzfWnLaD7^Q`q^9(EkA5aTqZG literal 0 HcmV?d00001 diff --git a/test/easy_ssl_test.exs b/test/easy_ssl_test.exs index 5e9cc77..2a89f73 100644 --- a/test/easy_ssl_test.exs +++ b/test/easy_ssl_test.exs @@ -122,4 +122,60 @@ defmodule EasySSLTest do assert get_in(cert, [:subject, :emailAddress]) == "mailbox@domain.tld" assert get_in(cert, [:issuer, :emailAddress]) == "mailbox@domain.tld" end + + test "parses attributes in subject in backwards compat manner" do + cert = File.read!(@der_cert_dir <> "www.espn.com.der") |> EasySSL.parse_der() + assert Map.has_key?(cert, :subject) + + # Attributes are parsed as before as single values. + assert cert.subject[:C] == "US" + + # The espn cert subject has zero OU attributes. Using parse_der without + # the multivalue option should result in same behavior pre-support for + # multivalue. I.e. the OU attribute should be nil. + assert cert.subject[:OU] == nil + end + + test "parses attributes in subject correctly with multivalue option" do + cert = File.read!(@der_cert_dir <> "www.espn.com.der") |> EasySSL.parse_der(multivalue: true) + assert Map.has_key?(cert, :subject) + + # Attributes are parsed as before as single values. + assert cert.subject[:C] == ["US"] + + # The espn cert subject has zero OU attributes. Using parse_der without + # the multivalue option should result in same behavior pre-support for + # multivalue. I.e. the OU attribute should be nil. + assert cert.subject[:OU] == [] + end + + test "parses issuer with multiple OU values in backwards compat manner" do + cert = File.read!(@der_cert_dir <> "www.espn.com.der") |> EasySSL.parse_der() + assert Map.has_key?(cert, :issuer) + + # The espn cert issuer has two OU attributes. Using parse_der without the + # multivalue option should result in same behavior pre-support for + # multivalue. I.e. the first OU attribute is discarded. + assert cert.issuer[:OU] == "(c) 2012 Entrust, Inc. - for authorized use only" + + # Likewise for aggregated, it should only contain the 2nd attribute. + assert cert.issuer.aggregated == "/C=US/CN=Entrust Certification Authority - L1K/O=Entrust, Inc./OU=(c) 2012 Entrust, Inc. - for authorized use only" + end + + test "parses issuer with multiple OU values correctly with multivalue option" do + cert = File.read!(@der_cert_dir <> "www.espn.com.der") |> EasySSL.parse_der(multivalue: true) + assert Map.has_key?(cert, :issuer) + + # The espn cert issuer has two OU attributes. Using parse_der with the + # multivalue option should result in a list containing both in the order + # they appear in the cert. + assert cert.issuer[:OU] == [ + "See www.entrust.net/legal-terms", + "(c) 2012 Entrust, Inc. - for authorized use only"] + + # Likewise for aggregated, it should only contain the both attribute + # values separated by a comma. + assert cert.issuer.aggregated == "/C=US/CN=Entrust Certification Authority - L1K/O=Entrust, Inc./OU=See www.entrust.net/legal-terms, (c) 2012 Entrust, Inc. - for authorized use only" + end + end From c5fdf3c97aca14335eb970d2b6a3a730c0f80706 Mon Sep 17 00:00:00 2001 From: Pete Kazmier Date: Sun, 30 Jun 2024 19:31:22 -0400 Subject: [PATCH 3/4] build: fix build for newer version of OTP This is my first foray into Elixir and the first code I've ever written, so I'm not too familiar with the build system, but I was unable to do anything until I made these changes. --- config/config.exs | 3 +-- mix.exs | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config/config.exs b/config/config.exs index 6cf955a..a3c1c57 100644 --- a/config/config.exs +++ b/config/config.exs @@ -1,7 +1,6 @@ # This file is responsible for configuring your application # and its dependencies with the aid of the Mix.Config module. -use Mix.Config - +import Config # This configuration is loaded before any dependency and is restricted # to this project. If another project depends on this project, this # file won't be loaded nor affect the parent project. For this reason, diff --git a/mix.exs b/mix.exs index 376be4a..8be1301 100644 --- a/mix.exs +++ b/mix.exs @@ -27,6 +27,7 @@ defmodule EasySSL.MixProject do {:excoveralls, "~> 0.8", only: :test}, {:ex_doc, "~> 0.16", only: :dev, runtime: false}, {:poison, "~> 2.0", only: :test}, + {:ssl_verify_fun, "~> 1.1", manager: :rebar3, override: true} ] end From 276edbd38418796775e97e0a19ea3f3ad2bcea77 Mon Sep 17 00:00:00 2001 From: Pete Kazmier Date: Sun, 30 Jun 2024 19:47:37 -0400 Subject: [PATCH 4/4] fix: change "return_base64" option to "serialize" to match parse_der It looks like someone refactored their code, but forgot to update the new name of this option in the parse_pem function definition. --- lib/easy_ssl.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/easy_ssl.ex b/lib/easy_ssl.ex index 71e58c2..8645f68 100644 --- a/lib/easy_ssl.ex +++ b/lib/easy_ssl.ex @@ -259,7 +259,7 @@ defmodule EasySSL do } """ def parse_pem(cert_charlist) when is_list(cert_charlist) do parse_pem(cert_charlist |> to_string) end - def parse_pem(cert_pem, opts \\ [all_domains: false, return_base64: false, multivalue: false]) do + def parse_pem(cert_pem, opts \\ [all_domains: false, serialize: false, multivalue: false]) do cert_regex = ~r/^\-{5}BEGIN\sCERTIFICATE\-{5}\n(?[^\-]+)\-{5}END\sCERTIFICATE\-{5}/ match = Regex.named_captures(cert_regex, cert_pem)