summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/x509.erl73
1 files changed, 27 insertions, 46 deletions
diff --git a/src/x509.erl b/src/x509.erl
index 32ade83..c815ca4 100644
--- a/src/x509.erl
+++ b/src/x509.erl
@@ -9,7 +9,6 @@
-type reason() :: {chain_too_long |
root_unknown |
- chain_broken |
signature_mismatch |
encoding_invalid}.
@@ -58,7 +57,10 @@ valid_chain_p(AcceptableRootCerts, [BottomCert|Rest], MaxChainLength) ->
Err -> Err
end.
-%% @doc Return first cert in list signing Cert, or notfound.
+%% @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;
@@ -68,15 +70,15 @@ signer(Cert, [H|T]) ->
{false, _} -> signer(Cert, T)
end.
-%% encoded_tbs_cert: verbatim from pubkey_cert.erl
-encoded_tbs_cert(Cert) ->
+%% Code from pubkey_cert:encoded_tbs_cert/1.
+encoded_tbs_cert(DerCert) ->
{ok, PKIXCert} =
- 'OTP-PUB-KEY':decode_TBSCert_exclusive(Cert),
- {'Certificate',
- {'Certificate_tbsCertificate', EncodedTBSCert}, _, _} = PKIXCert,
+ 'OTP-PUB-KEY':decode_TBSCert_exclusive(DerCert),
+ {'Certificate', {'Certificate_tbsCertificate', EncodedTBSCert}, _, _} =
+ PKIXCert,
EncodedTBSCert.
-%% extract_verify_data: close to pubkey_cert:extract_verify_data/2
+%% Code from pubkey_cert:extract_verify_data/2.
verifydata_from_cert(Cert, DerCert) ->
PlainText = encoded_tbs_cert(DerCert),
{_, Sig} = Cert#'Certificate'.signature,
@@ -85,18 +87,20 @@ verifydata_from_cert(Cert, DerCert) ->
{DigestType,_} = public_key:pkix_sign_types(SigAlg),
{PlainText, DigestType, Sig}.
-verify(Cert, DerCert,
- #'Certificate'{
+%% @doc Verify that Cert/DerCert is signed by Issuer.
+verify(Cert, DerCert, % Certificate to verify.
+ #'Certificate'{ % Issuer.
tbsCertificate = #'TBSCertificate'{
subjectPublicKeyInfo = IssuerSPKI}}) ->
- {DigestOrPlainText, DigestType, Signature} =
- verifydata_from_cert(Cert, DerCert),
+
+ %% Dig out digest, digest type and signature from Cert/DerCert.
+ {DigestOrPlainText, DigestType, Signature} = verifydata_from_cert(Cert,
+ DerCert),
+ %% Dig out issuer key from issuer cert.
#'SubjectPublicKeyInfo'{
algorithm = #'AlgorithmIdentifier'{algorithm = Alg, parameters = Params},
subjectPublicKey = {0, Key0}} = IssuerSPKI,
KeyType = pubkey_cert_records:supportedPublicKeyAlgorithms(Alg),
-
- %% public_key:pem_entry_decode()
IssuerKey =
case KeyType of
'RSAPublicKey' ->
@@ -107,43 +111,20 @@ verify(Cert, DerCert,
'ECPoint' ->
public_key:der_decode(KeyType, Key0)
end,
+
+ %% Verify the signature.
public_key:verify(DigestOrPlainText, DigestType, Signature, IssuerKey).
+%% @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()}.
signed_by_p(DerCert, IssuerDerCert) when is_binary(DerCert),
is_binary(IssuerDerCert) ->
- Cert = public_key:pkix_decode_cert(DerCert, plain),
- TBSCert = Cert#'Certificate'.tbsCertificate,
- IssuerCert = public_key:pkix_decode_cert(IssuerDerCert, plain),
- IssuerTBSCert = IssuerCert#'Certificate'.tbsCertificate,
- case pubkey_cert:is_issuer(TBSCert#'TBSCertificate'.issuer,
- IssuerTBSCert#'TBSCertificate'.subject) of
- false ->
- {false, chain_broken};
- true -> % Verify signature.
- case verify(Cert, DerCert, IssuerCert) of
- false -> {false, signature_mismatch};
- true -> true
- end
- end;
-signed_by_p(#'OTPCertificate'{} = Cert,
- #'OTPCertificate'{} = IssuerCert) ->
- %% FIXME: Validate presence and contents (against constraints) of
- %% names (subject, subjectAltName, emailAddress) too?
- case (catch public_key:pkix_is_issuer(Cert, IssuerCert)) of
- {'EXIT', Reason} ->
- lager:info("invalid certificate: ~p: ~p",
- [cert_string(Cert), Reason]),
- {false, encoding_invalid};
- true ->
- %% Cert.issuer does match IssuerCert.subject. Now verify
- %% the signature.
- case public_key:pkix_verify(Cert, public_key(IssuerCert)) of
- true -> true;
- false -> {false, signature_mismatch}
- end;
- false ->
- {false, chain_broken}
+ 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().