/
usr
/
lib64
/
erlang
/
lib
/
public_key-1.12
/
src
/
File Upload :
llllll
Current File: //usr/lib64/erlang/lib/public_key-1.12/src/pubkey_ocsp.erl
%% %% %CopyrightBegin% %% %% Copyright Ericsson AB 2008-2020. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at %% %% http://www.apache.org/licenses/LICENSE-2.0 %% %% Unless required by applicable law or agreed to in writing, software %% distributed under the License is distributed on an "AS IS" BASIS, %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions and %% limitations under the License. %% %% %CopyrightEnd% %% -module(pubkey_ocsp). -include("public_key.hrl"). -export([otp_cert/1, get_ocsp_responder_id/1, get_nonce_extn/1, decode_ocsp_response/1, verify_ocsp_response/3, get_acceptable_response_types_extn/0, find_single_response/3, ocsp_status/1]). ocsp_status({good, _}) -> valid; ocsp_status({unknown, Reason}) -> {bad_cert, {revocation_status_undetermined, Reason}}; ocsp_status({revoked, Reason}) -> {bad_cert, {revoked, Reason}}. %%-------------------------------------------------------------------- -spec verify_ocsp_response(binary(), list(), undefined | binary()) -> {ok, term()} | {error, term()}. %% %% Description: Verify the OCSP response to get the certificate status %%-------------------------------------------------------------------- verify_ocsp_response(OCSPResponseDer, ResponderCerts, Nonce) -> do_verify_ocsp_response( decode_ocsp_response(OCSPResponseDer), ResponderCerts, Nonce ). %%-------------------------------------------------------------------- -spec do_verify_ocsp_response({ok, #'BasicOCSPResponse'{}} | {error, term()}, list(), undefined | binary()) -> {ok, term()} | {error, term()}. %% %% Description: Verify the OCSP response to get the certificate status %%-------------------------------------------------------------------- do_verify_ocsp_response( {ok, #'BasicOCSPResponse'{ tbsResponseData = ResponseData, signatureAlgorithm = SignatureAlgo, signature = Signature, certs = Certs }}, ResponderCerts, Nonce) -> #'ResponseData'{ responderID = ResponderID } = ResponseData, case verify_ocsp_signature( public_key:der_encode('ResponseData', ResponseData), SignatureAlgo#'AlgorithmIdentifier'.algorithm, Signature, Certs ++ ResponderCerts, ResponderID) of ok -> verify_ocsp_nonce(ResponseData, Nonce); {error, Reason} -> {error, Reason} end; do_verify_ocsp_response({error, Reason}, _ResponderCerts, _Nonce) -> {error, Reason}. %%-------------------------------------------------------------------- -spec verify_ocsp_nonce(#'ResponseData'{}, undefined | binary()) -> {ok, term()} | {error, nonce_mismatch}. %% %% Description: Check if the nonces matches in OCSP response %%-------------------------------------------------------------------- verify_ocsp_nonce(ResponseData, Nonce) -> #'ResponseData'{ responses = Responses, responseExtensions = ResponseExtns } = ResponseData, case get_nonce_value(ResponseExtns) of Nonce -> {ok, Responses}; _Other -> {error, nonce_mismatch} end. %%-------------------------------------------------------------------- -spec get_nonce_value(asn1_NOVALUE | list()) -> undefined | binary(). %% %% Description: Get the nonce value from extensions %%-------------------------------------------------------------------- %% no extensions present in response get_nonce_value(asn1_NOVALUE) -> undefined; %% extensions exist, but no oscp nonce get_nonce_value([]) -> undefined; get_nonce_value([#'Extension'{ extnID = ?'id-pkix-ocsp-nonce', extnValue = Value} | _Extns]) -> Value; get_nonce_value([_Extn | Rest]) -> get_nonce_value(Rest). %%-------------------------------------------------------------------- -spec decode_ocsp_response(binary()) -> {ok, #'BasicOCSPResponse'{}} | {error, term()}. %% %% Description: Decode the OCSP response der %%-------------------------------------------------------------------- decode_ocsp_response(Response) -> Resp = public_key:der_decode('OCSPResponse', Response), case Resp#'OCSPResponse'.responseStatus of successful -> decode_response_bytes( Resp#'OCSPResponse'.responseBytes ); Error -> {error, Error} end. %%-------------------------------------------------------------------- -spec decode_response_bytes(#'ResponseBytes'{}) -> {ok, #'BasicOCSPResponse'{}} | {error, term()}. %% %% Description: Get basic ocsp response field %%-------------------------------------------------------------------- decode_response_bytes(#'ResponseBytes'{ responseType = ?'id-pkix-ocsp-basic', response = Data}) -> {ok, public_key:der_decode('BasicOCSPResponse', Data)}; decode_response_bytes(#'ResponseBytes'{responseType = RespType}) -> {error, {ocsp_response_type_not_supported, RespType}}. %%-------------------------------------------------------------------- -spec verify_ocsp_signature(binary(), term(), term(), list(), term()) -> ok | {error, term()}. %% %% Description: Verify the signature of OCSP response %%-------------------------------------------------------------------- verify_ocsp_signature( ResponseDataDer, SignatureAlgo, Signature, Certs, ResponderID) -> case find_responder_cert(ResponderID, Certs) of {ok, Cert} -> do_verify_ocsp_signature( ResponseDataDer, Signature, SignatureAlgo, Cert); {error, Reason} -> {error, Reason} end. %%-------------------------------------------------------------------- -spec find_responder_cert(term(), list()) -> {ok, #'Certificate'{} | #'OTPCertificate'{}} | {error, term()}. %% %% Description: Find the OCSP responder's cert in input list %%-------------------------------------------------------------------- find_responder_cert(_ResponderID, []) -> {error, ocsp_responder_cert_not_found}; find_responder_cert(ResponderID, [Cert | TCerts]) -> case is_responder(ResponderID, Cert) of true -> {ok, Cert}; false -> find_responder_cert(ResponderID, TCerts) end. %%-------------------------------------------------------------------- -spec do_verify_ocsp_signature( binary(), term(), term(), #'Certificate'{} | #'OTPCertificate'{}) -> ok | {error, term()}. %% %% Description: Verify the signature of OCSP response %%-------------------------------------------------------------------- do_verify_ocsp_signature(ResponseDataDer, Signature, AlgorithmID, Cert) -> {DigestType, _SignatureType} = public_key:pkix_sign_types(AlgorithmID), case public_key:verify( ResponseDataDer, DigestType, Signature, get_public_key_rec(Cert)) of true -> ok; false -> {error, ocsp_response_bad_signature} end. %%-------------------------------------------------------------------- -spec get_public_key_rec(#'Certificate'{} | #'OTPCertificate'{}) -> term(). %% %% Description: Get the subject public key field %%-------------------------------------------------------------------- get_public_key_rec(#'Certificate'{} = Cert) -> get_public_key_rec(otp_cert(Cert)); get_public_key_rec(#'OTPCertificate'{tbsCertificate = TbsCert}) -> PKInfo = TbsCert#'OTPTBSCertificate'.subjectPublicKeyInfo, PKInfo#'OTPSubjectPublicKeyInfo'.subjectPublicKey. %%-------------------------------------------------------------------- -spec is_responder(tuple(), #'Certificate'{} | #'OTPCertificate'{}) -> boolean(). %% %% Description: Check if is OCSP responder's cert %%-------------------------------------------------------------------- is_responder({byName, Name}, Cert) -> public_key:der_encode('Name', Name) == get_subject_name(Cert); is_responder({byKey, Key}, Cert) -> Key == crypto:hash(sha, get_public_key(Cert)). %%-------------------------------------------------------------------- -spec otp_cert(#'Certificate'{} | #'OTPCertificate'{} | binary()) -> #'OTPCertificate'{}. %% %% Description: Convert to #'OTPCertificate'{} %%-------------------------------------------------------------------- otp_cert(#'OTPCertificate'{} = Cert) -> Cert; otp_cert(#'Certificate'{} = Cert) -> public_key:pkix_decode_cert( public_key:der_encode('Certificate', Cert), otp); otp_cert(CertDer) when is_binary(CertDer) -> public_key:pkix_decode_cert(CertDer, otp). %%-------------------------------------------------------------------- -spec get_ocsp_responder_id(#'Certificate'{}) -> binary(). %% %% Description: Get the OCSP responder ID der %%-------------------------------------------------------------------- get_ocsp_responder_id(#'Certificate'{tbsCertificate = TbsCert}) -> public_key:der_encode( 'ResponderID', {byName, TbsCert#'TBSCertificate'.subject}). %%-------------------------------------------------------------------- -spec get_subject_name(#'Certificate'{} | #'OTPCertificate'{}) -> binary(). %% %% Description: Get the subject der from cert %%-------------------------------------------------------------------- get_subject_name(#'Certificate'{} = Cert) -> get_subject_name(otp_cert(Cert)); get_subject_name(#'OTPCertificate'{tbsCertificate = TbsCert}) -> public_key:pkix_encode('Name', TbsCert#'OTPTBSCertificate'.subject, otp). %%-------------------------------------------------------------------- -spec get_public_key(#'Certificate'{} | #'OTPCertificate'{}) -> binary(). %% %% Description: Get the public key from cert %%-------------------------------------------------------------------- get_public_key(#'Certificate'{} = Cert) -> get_public_key(otp_cert(Cert)); get_public_key(#'OTPCertificate'{tbsCertificate = TbsCert}) -> PKInfo = TbsCert#'OTPTBSCertificate'.subjectPublicKeyInfo, enc_pub_key(PKInfo#'OTPSubjectPublicKeyInfo'.subjectPublicKey). enc_pub_key(Key = #'RSAPublicKey'{}) -> public_key:der_encode('RSAPublicKey', Key); enc_pub_key({DsaInt, #'Dss-Parms'{}}) when is_integer(DsaInt) -> public_key:der_encode('DSAPublicKey', DsaInt); enc_pub_key({#'ECPoint'{point = Key}, _ECParam}) -> Key. %%-------------------------------------------------------------------- -spec get_nonce_extn(undefined | binary()) -> undefined | #'Extension'{}. %% %% Description: Get an OCSP nonce der %%-------------------------------------------------------------------- get_nonce_extn(undefined) -> undefined; get_nonce_extn(Nonce) when is_binary(Nonce) -> #'Extension'{ extnID = ?'id-pkix-ocsp-nonce', extnValue = Nonce }. %%-------------------------------------------------------------------- -spec get_acceptable_response_types_extn() -> #'Extension'{}. %% %% Description: Get an acceptable response types der %%-------------------------------------------------------------------- get_acceptable_response_types_extn() -> #'Extension'{ extnID = ?'id-pkix-ocsp-response', extnValue = public_key:der_encode( 'AcceptableResponses', [?'id-pkix-ocsp-basic']) }. %%-------------------------------------------------------------------- -spec get_serial_num(binary | #'Certificate'{} | #'OTPCertificate'{}) -> term(). %% %% Description: Get the serial number of a certificate %%-------------------------------------------------------------------- get_serial_num(Cert) -> #'OTPCertificate'{tbsCertificate = TbsCert} = otp_cert(Cert), TbsCert#'OTPTBSCertificate'.serialNumber. %%-------------------------------------------------------------------- %% -spec find_single_response(#'OTPCertificate'{}, #'OTPCertificate'{}, %% [#'SingleResponse'{}]) -> %% #'SingleResponse'{} | {error, no_matched_response}. %% %% %% Description: Find the matched single response. %%-------------------------------------------------------------------- find_single_response(Cert, IssuerCert, SingleResponseList) -> IssuerName = get_subject_name(IssuerCert), IssuerKey = get_public_key(IssuerCert), SerialNum = get_serial_num(Cert), match_single_response( IssuerName, IssuerKey, SerialNum, SingleResponseList). match_single_response(_IssuerName, _IssuerKey, _SerialNum, []) -> {error, no_matched_response}; match_single_response( IssuerName, IssuerKey, SerialNum, [#'SingleResponse'{ certID = #'CertID'{hashAlgorithm = Algo} = CertID } = Response | Responses]) -> HashType = public_key:pkix_hash_type( Algo#'AlgorithmIdentifier'.algorithm), case (SerialNum == CertID#'CertID'.serialNumber) andalso (crypto:hash( HashType, IssuerName) == CertID#'CertID'.issuerNameHash) andalso (crypto:hash( HashType, IssuerKey) == CertID#'CertID'.issuerKeyHash) of true -> {ok, Response}; false -> match_single_response(IssuerName, IssuerKey, SerialNum, Responses) end.
Copyright ©2k19 -
Hexid
|
Tex7ure