diff options
-rw-r--r-- | src/catlfish.erl | 20 | ||||
-rw-r--r-- | src/x509.erl | 50 |
2 files changed, 21 insertions, 49 deletions
diff --git a/src/catlfish.erl b/src/catlfish.erl index 3b81baa..50811a1 100644 --- a/src/catlfish.erl +++ b/src/catlfish.erl @@ -91,24 +91,12 @@ serialise_signature_type(certificate_timestamp) -> <<0:8>>; serialise_signature_type(tree_hash) -> <<1:8>>. -%% deserialise_signature_type(<<0:8>>) -> -%% certificate_timestamp; -%% deserialise_signature_type(<<1:8>>) -> -%% tree_hash. - -%% build_mtl(Timestamp, LeafCert) -> -%% TSE = #timestamped_entry{timestamp = Timestamp, -%% entry_type = x509_entry, -%% signed_entry = LeafCert}, -%% MTL = #mtl{leaf_version = v1, -%% leaf_type = timestamped_entry, -%% entry = TSE}, -%% serialise(MTL). calc_sct(TimestampedEntry) -> - plop:serialise(plop:spt(list_to_binary([<<?PROTOCOL_VERSION:8>>, - serialise_signature_type(certificate_timestamp), - serialise(TimestampedEntry)]))). + plop:serialise( + plop:spt(list_to_binary([<<?PROTOCOL_VERSION:8>>, + serialise_signature_type(certificate_timestamp), + serialise(TimestampedEntry)]))). get_sct(Hash, TimestampedEntry) -> case application:get_env(catlfish, sctcache_root_path) of diff --git a/src/x509.erl b/src/x509.erl index 43b90b3..e8c4f2b 100644 --- a/src/x509.erl +++ b/src/x509.erl @@ -14,6 +14,9 @@ encoding_invalid}. -define(MAX_CHAIN_LENGTH, 10). +-define(LEAF_POISON_OID, {1,3,6,1,4,1,11129,2,4,3}). +-define(LEAF_POISON_VAL, [5,0]). +-define(CA_POISON_OID, {1,3,6,1,4,1,11129,2,4,4}). -spec normalise_chain([binary()], [binary()]) -> {ok, [binary()]} | {error, reason()}. @@ -41,9 +44,7 @@ read_pemfiles_from_dir(Dir) -> []; {ok, Filenames} -> Files = lists:filter( - fun(F) -> - string:equal(".pem", filename:extension(F)) - end, + fun(F) -> string:equal(".pem", filename:extension(F)) end, Filenames), ders_from_pemfiles(Dir, Files) end. @@ -61,6 +62,8 @@ detox(LeafDer, ChainDer) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Private functions. +-spec normalise_chain([binary()], [binary()], integer()) -> + {false, reason()} | {true, list()}. %% @doc Verify that the leaf cert or precert has a valid chain back to %% an acceptable root cert. The order of certificates in the second %% argument is: leaf cert in head, chain in tail. Order of first @@ -71,8 +74,6 @@ detox(LeafDer, ChainDer) -> %% amongst the acceptable root certs. Otherwise it contains exactly %% one element, a CA cert from the acceptable root certs signing the %% root of the chain. --spec normalise_chain([binary()], [binary()], integer()) -> - {false, reason()} | {true, list()}. normalise_chain(_, _, MaxChainLength) when MaxChainLength =< 0 -> %% Chain too long. {false, chain_too_long}; @@ -98,11 +99,11 @@ normalise_chain(AcceptableRootCerts, [BottomCert|Rest], MaxChainLength) -> false -> {false, signature_mismatch} end. +-spec signer(binary(), [binary()]) -> notfound | binary(). %% @doc Return first cert in list signing Cert, or notfound. NOTE: %% This is potentially expensive. It'd be more efficient to search for %% Cert.issuer in a list of Issuer.subject's. If so, maybe make the %% matching somewhat fuzzy unless that too is expensive. --spec signer(binary(), [binary()]) -> notfound | binary(). signer(_Cert, []) -> notfound; signer(Cert, [H|T]) -> @@ -132,7 +133,6 @@ extract_verify_data(Cert, DerCert) -> {_, Sig} = Cert#'Certificate'.signature, SigAlgRecord = Cert#'Certificate'.signatureAlgorithm, SigAlg = SigAlgRecord#'AlgorithmIdentifier'.algorithm, - lager:debug("SigAlg: ~p", [SigAlg]), try {DigestType, _} = public_key:pkix_sign_types(SigAlg), {ok, {PlainText, DigestType, Sig}} @@ -160,10 +160,6 @@ verify_sig2(IssuerSPKI, {DigestOrPlainText, DigestType, Signature}) -> algorithm = #'AlgorithmIdentifier'{algorithm = Alg, parameters = Params}, subjectPublicKey = {0, Key0}} = IssuerSPKI, KeyType = pubkey_cert_records:supportedPublicKeyAlgorithms(Alg), - lager:debug("Alg: ~p", [Alg]), - lager:debug("Params: ~p", [Params]), - lager:debug("KeyType: ~p", [KeyType]), - lager:debug("Key0: ~p", [Key0]), IssuerKey = case KeyType of 'RSAPublicKey' -> @@ -176,12 +172,6 @@ verify_sig2(IssuerSPKI, {DigestOrPlainText, DigestType, Signature}) -> lager:error("NIY: Issuer key type ~p", [KeyType]), false end, - - lager:debug("DigestOrPlainText: ~p", [DigestOrPlainText]), - lager:debug("DigestType: ~p", [DigestType]), - lager:debug("Signature: ~p", [Signature]), - lager:debug("IssuerKey: ~p", [IssuerKey]), - %% Verify the signature. public_key:verify(DigestOrPlainText, DigestType, Signature, IssuerKey). @@ -208,23 +198,23 @@ parsable_cert_p(Der) -> end. %% Precerts according to RFC6962. - +%% %% Submitted precerts have a special critical poison extension -- OID %% 1.3.6.1.4.1.11129.2.4.3, whose extnValue OCTET STRING contains %% ASN.1 NULL data (0x05 0x00). - +%% %% They are signed with either the CA cert that will sign the final %% cert or a Precertificate Signing Certificate directly signed by the %% CA cert that will sign the final cert. A Precertificate Signing %% Certificate has CA:true and Extended Key Usage: Certificate %% Transparency, OID 1.3.6.1.4.1.11129.2.4.4. - +%% %% PreCert in SignedCertificateTimestamp does _not_ contain the poison %% extension, nor does it have an issuer which is a Precertificate %% Signing Certificate. This means that we have to 1) remove the %% poison extension and 2) potentially change issuer and Authority Key %% Identifier. See RFC6962 Section 3.2. - +%% %% Changes in draft-ietf-trans-rfc6962-bis-??: TODO. -spec detox_precert(binary(), binary(), binary()) -> {binary(), binary()}. @@ -282,17 +272,15 @@ set_issuer_and_authkeyid(TBSCert, lager:debug("swapping auth key id to ~p", [ParentAuthKeyExt]), ParentAuthKeyExt; - Orig -> - Orig + _ -> E end end, TBSCert#'TBSCertificate'.extensions), + lager:debug("setting issuer and auth key id", []), TBSCert#'TBSCertificate'{issuer = ParentIssuer, extensions = NewExtensions} end. --define(CA_POISON_OID, {1,3,6,1,4,1,11129,2,4,4}). - -spec is_precert_signer(#'Certificate'{}) -> boolean(). is_precert_signer(#'Certificate'{tbsCertificate = TBSCert}) -> Extensions = pubkey_cert:extensions_list(TBSCert#'TBSCertificate'.extensions), @@ -323,14 +311,10 @@ is_ca(#'TBSCertificate'{extensions = Extensions}) -> -spec remove_poison_ext(#'Certificate'{}) -> #'TBSCertificate'{}. remove_poison_ext(#'Certificate'{tbsCertificate = TBSCert}) -> - Extensions = pubkey_cert:extensions_list(TBSCert#'TBSCertificate'.extensions), - SanitisedExtensions = - filter(fun(E) -> not poisoned_leaf_p(E) end, Extensions), - NewTBSCert = TBSCert#'TBSCertificate'{extensions = SanitisedExtensions}, - NewTBSCert. - --define(LEAF_POISON_OID, {1,3,6,1,4,1,11129,2,4,3}). --define(LEAF_POISON_VAL, [5,0]). + Extensions = + filter(fun(E) -> not poisoned_leaf_p(E) end, + pubkey_cert:extensions_list(TBSCert#'TBSCertificate'.extensions)), + TBSCert#'TBSCertificate'{extensions = Extensions}. poisoned_leaf_p(#'Extension'{extnID = ?LEAF_POISON_OID, critical = true, |