summaryrefslogtreecommitdiff
path: root/src/x509.erl
diff options
context:
space:
mode:
authorLinus Nordberg <linus@nordberg.se>2015-02-27 01:55:15 +0100
committerLinus Nordberg <linus@nordberg.se>2015-02-27 01:55:15 +0100
commitb41acdada125a41c40e94177b8ebdc2bb7d130b6 (patch)
treea49cd34049032f0f9c07d9bbd030de26f92f3af7 /src/x509.erl
parent93b37a60e4faf21abbc65a7e9d4b323302b32942 (diff)
Fix a bug where verification of EC signatures made us crash.
Also, have valid_chain_p return boolean, add some debug logging and detect invalid signature types instead of crashing.
Diffstat (limited to 'src/x509.erl')
-rw-r--r--src/x509.erl73
1 files changed, 40 insertions, 33 deletions
diff --git a/src/x509.erl b/src/x509.erl
index 9030e04..5a0e871 100644
--- a/src/x509.erl
+++ b/src/x509.erl
@@ -61,7 +61,7 @@ valid_chain_p(AcceptableRootCerts, [TopCert], MaxChainLength) ->
valid_chain_p(AcceptableRootCerts, [BottomCert|Rest], MaxChainLength) ->
case signed_by_p(BottomCert, hd(Rest)) of
true -> valid_chain_p(AcceptableRootCerts, Rest, MaxChainLength - 1);
- Err -> Err
+ false -> {false, signature_mismatch}
end.
%% @doc Return first cert in list signing Cert, or notfound. NOTE:
@@ -72,9 +72,14 @@ valid_chain_p(AcceptableRootCerts, [BottomCert|Rest], MaxChainLength) ->
signer(_Cert, []) ->
notfound;
signer(Cert, [H|T]) ->
+ lager:debug("Is ~p signed by ~p?", [cert_string(Cert), cert_string(H)]),
case signed_by_p(Cert, H) of
- true -> H;
- {false, _} -> signer(Cert, T)
+ true ->
+ lager:debug("~p is signed by ~p",
+ [cert_string(Cert), cert_string(H)]),
+ H;
+ false ->
+ signer(Cert, T)
end.
%% Code from pubkey_cert:encoded_tbs_cert/1.
@@ -86,40 +91,55 @@ encoded_tbs_cert(DerCert) ->
EncodedTBSCert.
%% Code from pubkey_cert:extract_verify_data/2.
+-spec verifydata_from_cert(#'Certificate'{}, binary()) -> {ok, tuple()} | error.
verifydata_from_cert(Cert, DerCert) ->
PlainText = encoded_tbs_cert(DerCert),
{_, Sig} = Cert#'Certificate'.signature,
SigAlgRecord = Cert#'Certificate'.signatureAlgorithm,
SigAlg = SigAlgRecord#'AlgorithmIdentifier'.algorithm,
- {DigestType,_} = public_key:pkix_sign_types(SigAlg),
- {PlainText, DigestType, Sig}.
+ lager:debug("SigAlg: ~p", [SigAlg]),
+ try
+ {DigestType, _} = public_key:pkix_sign_types(SigAlg),
+ {ok, {PlainText, DigestType, Sig}}
+ catch
+ error:function_clause ->
+ lager:debug("signature algorithm not supported: ~p", [SigAlg]),
+ error
+ end.
%% @doc Verify that Cert/DerCert is signed by Issuer.
-verify(Cert, DerCert, % Certificate to verify.
- #'Certificate'{ % Issuer.
- tbsCertificate = #'TBSCertificate'{
- subjectPublicKeyInfo = IssuerSPKI}}) ->
-
+-spec verify_sig(#'Certificate'{}, binary(), #'Certificate'{}) -> boolean().
+verify_sig(Cert, DerCert, % Certificate to verify.
+ #'Certificate'{ % Issuer.
+ tbsCertificate = #'TBSCertificate'{
+ subjectPublicKeyInfo = IssuerSPKI}}) ->
%% Dig out digest, digest type and signature from Cert/DerCert.
- {DigestOrPlainText, DigestType, Signature} = verifydata_from_cert(Cert,
- DerCert),
+ case verifydata_from_cert(Cert, DerCert) of
+ error -> false;
+ {ok, Tuple} -> verify_sig2(IssuerSPKI, Tuple)
+ end.
+
+verify_sig2(IssuerSPKI, {DigestOrPlainText, DigestType, Signature}) ->
%% Dig out issuer key from issuer cert.
#'SubjectPublicKeyInfo'{
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' ->
public_key:der_decode(KeyType, Key0);
- 'DSAPublicKey' ->
- {params, DssParams} = public_key:der_decode('DSAParams', Params),
- {public_key:der_decode(KeyType, Key0), DssParams};
'ECPoint' ->
- public_key:der_decode(KeyType, Key0)
+ Point = #'ECPoint'{point = Key0},
+ ECParams = public_key:der_decode('EcpkParameters', Params),
+ {Point, ECParams};
+ _ -> % FIXME: 'DSAPublicKey'
+ lager:error("NIY: Issuer key type ~p", [KeyType]),
+ false
end,
lager:debug("DigestOrPlainText: ~p", [DigestOrPlainText]),
@@ -132,25 +152,12 @@ verify(Cert, DerCert, % Certificate to verify.
%% @doc Is Cert signed by Issuer? Only verify that the signature
%% matches and don't check things like Cert.issuer == Issuer.subject.
--spec signed_by_p(binary(), binary()) -> true | {false, reason()}.
+-spec signed_by_p(binary(), binary()) -> boolean().
signed_by_p(DerCert, IssuerDerCert) when is_binary(DerCert),
is_binary(IssuerDerCert) ->
- case verify(public_key:pkix_decode_cert(DerCert, plain),
- DerCert,
- public_key:pkix_decode_cert(IssuerDerCert, plain)) of
- false -> {false, signature_mismatch};
- true -> true
- end.
-
--spec public_key(binary() | #'OTPCertificate'{}) -> public_key:public_key().
-public_key(CertDer) when is_binary(CertDer) ->
- public_key(public_key:pkix_decode_cert(CertDer, otp));
-public_key(#'OTPCertificate'{
- tbsCertificate =
- #'OTPTBSCertificate'{subjectPublicKeyInfo =
- #'OTPSubjectPublicKeyInfo'{
- subjectPublicKey = Key}}}) ->
- Key.
+ verify_sig(public_key:pkix_decode_cert(DerCert, plain),
+ DerCert,
+ public_key:pkix_decode_cert(IssuerDerCert, plain)).
cert_string(Der) ->
mochihex:to_hex(crypto:hash(sha, Der)).