From f657835170dd8e48e70bf962de92fd84cfc69aeb Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Fri, 20 Mar 2015 07:01:52 +0100 Subject: WIP, precerts signed by non-precert intermediates --- src/x509.erl | 85 ++++++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 63 insertions(+), 22 deletions(-) (limited to 'src/x509.erl') diff --git a/src/x509.erl b/src/x509.erl index 278686b..d088624 100644 --- a/src/x509.erl +++ b/src/x509.erl @@ -228,20 +228,22 @@ parsable_cert_p(Der) -> %% Changes in draft-ietf-trans-rfc6962-bis-??: TODO. -spec detox_precert(binary(), binary(), binary()) -> {binary(), binary()}. +%% @doc Return {DetoxedLeaf, IssuerPubKeyHash} where i) DetoxedLeaf is +%% the tbsCertificate w/o poison and adjusted issuer and authkeyid; +%% and ii) IssuerPubKeyHash is the hash over issuing cert's public +%% key. detox_precert(LeafDer, ParentDer, GrandParentDer) -> Leaf = public_key:pkix_decode_cert(LeafDer, plain), Parent = public_key:pkix_decode_cert(ParentDer, plain), GrandParent = public_key:pkix_decode_cert(GrandParentDer, plain), - DetoxedLeafTBS = remove_poison_ext(Leaf), %% If parent is a precert signing cert, change issuer and - %% authority key id to refer to grandparent. + %% potential authority key id to refer to grandparent. {C, IssuerKeyHash} = case is_precert_signer(Parent) of true -> - GrandParent = public_key:pkix_decode_cert(GrandParentDer, plain), - {change_issuer(DetoxedLeafTBS, GrandParent), + {set_issuer_and_authkeyid(DetoxedLeafTBS, Parent), extract_pub_key(GrandParent)}; false -> {DetoxedLeafTBS, extract_pub_key(Parent)} @@ -256,34 +258,73 @@ extract_pub_key(#'Certificate'{ subjectPublicKeyInfo = SPKI}}) -> SPKI. -change_issuer(Cert, _) -> - %% FIXME: NIY. - Cert. - --spec is_precert_signer(#'Certificate'{}) -> boolean(). -is_precert_signer(Cert) -> - %%ca_cert_p(Cert) and has_critext(Cert, {1,3,6,1,4,1,11129,2,4,4}. - ca_cert_p(Cert), false. % FIXME: NIY +-spec set_issuer_and_authkeyid(#'TBSCertificate'{}, #'Certificate'{}) -> + #'TBSCertificate'{}. +%% @doc Return Cert with issuer and AuthorityKeyIdentifier from Parent. +set_issuer_and_authkeyid(TBSCert, + #'Certificate'{ + tbsCertificate = + #'TBSCertificate'{ + issuer = ParentIssuer, + extensions = ParentExtensions}}) -> + case pubkey_cert:select_extension(?'id-ce-authorityKeyIdentifier', + ParentExtensions) of + undefined -> + lager:debug("setting issuer only", []), + TBSCert#'TBSCertificate'{issuer = ParentIssuer}; + ParentAuthKeyExt -> + NewExtensions = + lists:map( + fun(E) -> + case E of + #'Extension'{extnID = + ?'id-ce-authorityKeyIdentifier'} -> + lager:debug("swapping auth key id to ~p", + [ParentAuthKeyExt]), + ParentAuthKeyExt; + Orig -> + Orig + end + end, + TBSCert#'TBSCertificate'.extensions), + TBSCert#'TBSCertificate'{issuer = ParentIssuer, + extensions = NewExtensions} + end. --spec ca_cert_p(#'Certificate'{}) -> boolean(). -ca_cert_p(Cert) -> - %% TBS = Cert#'Certificate'.tbsCertificate, - %% {ExtnID, Critical, ExtnValue} = TBS#'TBSCertificate'.extensions, - Cert. % FIXME: NIY +-define(CA_POISON_OID, {1,3,6,1,4,1,11129,2,4,4}). --define(LEAF_POISON_OID, {1,3,6,1,4,1,11129,2,4,3}). --define(LEAF_POISON_VAL, asn1_NOVALUE). +-spec is_precert_signer(#'Certificate'{}) -> boolean(). +is_precert_signer(#'Certificate'{tbsCertificate = TBSCert}) -> + Extensions = pubkey_cert:extensions_list(TBSCert#'TBSCertificate'.extensions), + case pubkey_cert:select_extension(?'id-ce-extKeyUsage', Extensions) of + #'Extension'{extnValue = [_|?CA_POISON_OID]} -> + case pubkey_cert:select_extension(?'id-ce-basicConstraints', + Extensions) of + #'Extension'{critical = true, + extnValue = #'BasicConstraints'{cA = true}} -> + lager:debug("found precert signer", []), + true; + E -> + lager:debug("found poisonous ca oid but cA != true: ~p", + [E]), + false + end; + E -> + lager:debug("didn't find poisonous ca oid, only ~p", [E]), + false + end. -spec remove_poison_ext(#'Certificate'{}) -> #'TBSCertificate'{}. -remove_poison_ext(Cert) -> - TBSCert = Cert#'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}, - %%Cert#'Certificate'{tbsCertificate = NewTBSCert}. NewTBSCert. +-define(LEAF_POISON_OID, {1,3,6,1,4,1,11129,2,4,3}). +-define(LEAF_POISON_VAL, [5,0]). + poisoned_leaf_p(#'Extension'{extnID = ?LEAF_POISON_OID, critical = true, extnValue = ?LEAF_POISON_VAL}) -> -- cgit v1.1