summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Nordberg <linus@nordberg.se>2015-03-20 07:01:52 +0100
committerLinus Nordberg <linus@nordberg.se>2015-03-20 07:01:52 +0100
commitf657835170dd8e48e70bf962de92fd84cfc69aeb (patch)
treed8465c23ec03ddbb51ea8a538e0526f5d7855582
parent74ba2bfa84948ccdd6965081120f544f3504ed9b (diff)
WIP, precerts signed by non-precert intermediates
-rw-r--r--src/x509.erl85
1 files changed, 63 insertions, 22 deletions
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}) ->