Latest update.
This commit is contained in:
@@ -1,3 +1,3 @@
|
||||
LIBS=../../libcrypto
|
||||
SOURCE[../../libcrypto]= cmp_asn.c cmp_ctx.c cmp_err.c cmp_util.c \
|
||||
cmp_status.c cmp_hdr.c cmp_protect.c cmp_msg.c
|
||||
cmp_status.c cmp_hdr.c cmp_protect.c cmp_msg.c cmp_vfy.c
|
||||
@@ -73,7 +73,8 @@ ASN1_SEQUENCE(OSSL_CMP_ERRORMSGCONTENT) = {
|
||||
IMPLEMENT_ASN1_FUNCTIONS(OSSL_CMP_ERRORMSGCONTENT)
|
||||
|
||||
ASN1_ADB_TEMPLATE(infotypeandvalue_default) = ASN1_OPT(OSSL_CMP_ITAV,
|
||||
infoValue.other, ASN1_ANY);
|
||||
infoValue.other,
|
||||
ASN1_ANY);
|
||||
/* ITAV means InfoTypeAndValue */
|
||||
ASN1_ADB(OSSL_CMP_ITAV) = {
|
||||
/* OSSL_CMP_CMPCERTIFICATE is effectively X509 so it is used directly */
|
||||
|
||||
+56
-5
@@ -80,7 +80,7 @@ int OSSL_CMP_CTX_set1_untrusted_certs(OSSL_CMP_CTX *ctx, STACK_OF(X509) *certs)
|
||||
sk_X509_pop_free(ctx->untrusted_certs, X509_free);
|
||||
ctx->untrusted_certs = untrusted_certs;
|
||||
return 1;
|
||||
err:
|
||||
err:
|
||||
sk_X509_pop_free(untrusted_certs, X509_free);
|
||||
return 0;
|
||||
}
|
||||
@@ -301,7 +301,7 @@ static size_t ossl_cmp_log_trace_cb(const char *buf, size_t cnt,
|
||||
int category, int cmd, void *vdata)
|
||||
{
|
||||
OSSL_CMP_CTX *ctx = vdata;
|
||||
const char *prefix_msg;
|
||||
const char *msg;
|
||||
OSSL_CMP_severity level = -1;
|
||||
char *func = NULL;
|
||||
char *file = NULL;
|
||||
@@ -312,14 +312,14 @@ static size_t ossl_cmp_log_trace_cb(const char *buf, size_t cnt,
|
||||
if (ctx->log_cb == NULL)
|
||||
return 1; /* silently drop message */
|
||||
|
||||
prefix_msg = ossl_cmp_log_parse_metadata(buf, &level, &func, &file, &line);
|
||||
msg = ossl_cmp_log_parse_metadata(buf, &level, &func, &file, &line);
|
||||
|
||||
if (level > ctx->log_verbosity) /* excludes the case level is unknown */
|
||||
goto end; /* suppress output since severity is not sufficient */
|
||||
|
||||
if (!ctx->log_cb(func != NULL ? func : "(no func)",
|
||||
file != NULL ? file : "(no file)",
|
||||
line, level, prefix_msg))
|
||||
line, level, msg))
|
||||
cnt = 0;
|
||||
|
||||
end:
|
||||
@@ -329,6 +329,57 @@ static size_t ossl_cmp_log_trace_cb(const char *buf, size_t cnt,
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Print CMP log messages (i.e., diagnostic info) via the log cb of the ctx */
|
||||
int ossl_cmp_print_log(OSSL_CMP_severity level, const OSSL_CMP_CTX *ctx,
|
||||
const char *func, const char *file, int line,
|
||||
const char *level_str, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
char hugebuf[1024 * 2];
|
||||
int res = 0;
|
||||
|
||||
if (ctx == NULL || ctx->log_cb == NULL)
|
||||
return 1; /* silently drop message */
|
||||
|
||||
if (level > ctx->log_verbosity) /* excludes the case level is unknown */
|
||||
return 1; /* suppress output since severity is not sufficient */
|
||||
|
||||
if (format == NULL)
|
||||
return 0;
|
||||
|
||||
va_start(args, format);
|
||||
|
||||
if (func == NULL)
|
||||
func = "(unset function name)";
|
||||
if (file == NULL)
|
||||
file = "(unset file name)";
|
||||
if (level_str == NULL)
|
||||
level_str = "(unset level string)";
|
||||
|
||||
#ifndef OPENSSL_NO_TRACE
|
||||
if (OSSL_TRACE_ENABLED(CMP)) {
|
||||
OSSL_TRACE_BEGIN(CMP) {
|
||||
int printed =
|
||||
BIO_snprintf(hugebuf, sizeof(hugebuf),
|
||||
"%s:%s:%d:" OSSL_CMP_LOG_PREFIX "%s: ",
|
||||
func, file, line, level_str);
|
||||
if (printed > 0 && (size_t)printed < sizeof(hugebuf)) {
|
||||
if (BIO_vsnprintf(hugebuf + printed,
|
||||
sizeof(hugebuf) - printed, format, args) > 0)
|
||||
res = BIO_puts(trc_out, hugebuf) > 0;
|
||||
}
|
||||
} OSSL_TRACE_END(CMP);
|
||||
}
|
||||
#else /* compensate for disabled trace API */
|
||||
{
|
||||
if (BIO_vsnprintf(hugebuf, sizeof(hugebuf), format, args) > 0)
|
||||
res = ctx->log_cb(func, file, line, level, hugebuf);
|
||||
}
|
||||
#endif
|
||||
va_end(args);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set a callback function for error reporting and logging messages.
|
||||
* Returns 1 on success, 0 on error
|
||||
@@ -768,7 +819,7 @@ int OSSL_CMP_CTX_set1_transactionID(OSSL_CMP_CTX *ctx,
|
||||
* returns 1 on success, 0 on error
|
||||
*/
|
||||
int ossl_cmp_ctx_set1_recipNonce(OSSL_CMP_CTX *ctx,
|
||||
const ASN1_OCTET_STRING *nonce)
|
||||
const ASN1_OCTET_STRING *nonce)
|
||||
{
|
||||
if (!ossl_assert(ctx != NULL))
|
||||
return 0;
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
#ifndef OPENSSL_NO_ERR
|
||||
|
||||
static const ERR_STRING_DATA CMP_str_reasons[] = {
|
||||
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_ALGORITHM_NOT_SUPPORTED),
|
||||
"algorithm not supported"},
|
||||
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_BAD_REQUEST_ID), "bad request id"},
|
||||
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_CERTID_NOT_FOUND), "certid not found"},
|
||||
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_CERTIFICATE_NOT_FOUND),
|
||||
@@ -50,6 +52,10 @@ static const ERR_STRING_DATA CMP_str_reasons[] = {
|
||||
"error protecting message"},
|
||||
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_ERROR_SETTING_CERTHASH),
|
||||
"error setting certhash"},
|
||||
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_ERROR_VALIDATING_PROTECTION),
|
||||
"error validating protection"},
|
||||
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_FAILED_EXTRACTING_PUBKEY),
|
||||
"failed extracting pubkey"},
|
||||
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_FAILURE_OBTAINING_RANDOM),
|
||||
"failure obtaining random"},
|
||||
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_FAIL_INFO_OUT_OF_RANGE),
|
||||
@@ -57,19 +63,38 @@ static const ERR_STRING_DATA CMP_str_reasons[] = {
|
||||
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_INVALID_ARGS), "invalid args"},
|
||||
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_MISSING_KEY_INPUT_FOR_CREATING_PROTECTION),
|
||||
"missing key input for creating protection"},
|
||||
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_MISSING_KEY_USAGE_DIGITALSIGNATURE),
|
||||
"missing key usage digitalsignature"},
|
||||
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_MISSING_PRIVATE_KEY),
|
||||
"missing private key"},
|
||||
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_MISSING_PROTECTION), "missing protection"},
|
||||
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_MISSING_SENDER_IDENTIFICATION),
|
||||
"missing sender identification"},
|
||||
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_MISSING_TRUST_STORE),
|
||||
"missing trust store"},
|
||||
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_MULTIPLE_SAN_SOURCES),
|
||||
"multiple san sources"},
|
||||
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_NO_STDIO), "no stdio"},
|
||||
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_NO_SUITABLE_SENDER_CERT),
|
||||
"no suitable sender cert"},
|
||||
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_NULL_ARGUMENT), "null argument"},
|
||||
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_PKIBODY_ERROR), "pkibody error"},
|
||||
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_PKISTATUSINFO_NOT_FOUND),
|
||||
"pkistatusinfo not found"},
|
||||
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_POTENTIALLY_INVALID_CERTIFICATE),
|
||||
"potentially invalid certificate"},
|
||||
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_RECIPNONCE_UNMATCHED),
|
||||
"recipnonce unmatched"},
|
||||
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_REQUEST_NOT_ACCEPTED),
|
||||
"request not accepted"},
|
||||
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_SENDER_GENERALNAME_TYPE_NOT_SUPPORTED),
|
||||
"sender generalname type not supported"},
|
||||
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_SRVCERT_DOES_NOT_VALIDATE_MSG),
|
||||
"srvcert does not validate msg"},
|
||||
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_TRANSACTIONID_UNMATCHED),
|
||||
"transactionid unmatched"},
|
||||
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNEXPECTED_PKIBODY), "unexpected pkibody"},
|
||||
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNEXPECTED_PVNO), "unexpected pvno"},
|
||||
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNKNOWN_ALGORITHM_ID),
|
||||
"unknown algorithm id"},
|
||||
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNKNOWN_CERT_TYPE), "unknown cert type"},
|
||||
@@ -77,8 +102,11 @@ static const ERR_STRING_DATA CMP_str_reasons[] = {
|
||||
"unsupported algorithm"},
|
||||
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNSUPPORTED_KEY_TYPE),
|
||||
"unsupported key type"},
|
||||
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNSUPPORTED_PROTECTION_ALG_DHBASEDMAC),
|
||||
"unsupported protection alg dhbasedmac"},
|
||||
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_WRONG_ALGORITHM_OID),
|
||||
"wrong algorithm oid"},
|
||||
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_WRONG_PBM_VALUE), "wrong pbm value"},
|
||||
{0, NULL}
|
||||
};
|
||||
|
||||
|
||||
+129
-52
@@ -48,16 +48,23 @@ struct ossl_cmp_ctx_st {
|
||||
void *http_cb_arg; /* allows to store optional argument to cb */
|
||||
|
||||
/* server authentication */
|
||||
int unprotectedErrors; /* accept neg. response with no/invalid protection */
|
||||
/* to cope with broken server */
|
||||
/*
|
||||
* unprotectedErrors may be set as workaround for broken server responses:
|
||||
* accept missing or invalid protection of regular error messages, negative
|
||||
* certificate responses (ip/cp/kup), revocation responses (rp), and PKIConf
|
||||
*/
|
||||
int unprotectedErrors;
|
||||
X509 *srvCert; /* certificate used to identify the server */
|
||||
X509 *validatedSrvCert; /* caches any already validated server cert */
|
||||
X509_NAME *expected_sender; /* expected sender in pkiheader of response */
|
||||
X509_STORE *trusted; /* trust store maybe w CRLs and cert verify callback */
|
||||
STACK_OF(X509) *untrusted_certs; /* untrusted (intermediate) certs */
|
||||
int ignore_keyusage; /* ignore key usage entry when validating certs */
|
||||
int permitTAInExtraCertsForIR; /* allow use of root certs in extracerts */
|
||||
/* when validating message protection; used for 3GPP-style E.7 */
|
||||
/*
|
||||
* permitTAInExtraCertsForIR allows use of root certs in extracerts
|
||||
* when validating message protection; this is used for 3GPP-style E.7
|
||||
*/
|
||||
int permitTAInExtraCertsForIR;
|
||||
|
||||
/* client authentication */
|
||||
int unprotectedSend; /* send unprotected PKI messages */
|
||||
@@ -536,68 +543,108 @@ typedef struct ossl_cmp_pkibody_st {
|
||||
OSSL_CMP_CERTREPMESSAGE *ip; /* 1 */
|
||||
OSSL_CRMF_MSGS *cr; /* 2 */
|
||||
OSSL_CMP_CERTREPMESSAGE *cp; /* 3 */
|
||||
/* p10cr [4] CertificationRequest, --imported from [PKCS10] */
|
||||
/*
|
||||
/*-
|
||||
* p10cr [4] CertificationRequest, --imported from [PKCS10]
|
||||
*
|
||||
* PKCS10_CERTIFICATIONREQUEST is effectively X509_REQ
|
||||
* so it is used directly
|
||||
*/
|
||||
X509_REQ *p10cr; /* 4 */
|
||||
/* popdecc [5] POPODecKeyChallContent, --pop Challenge */
|
||||
/* POPODecKeyChallContent ::= SEQUENCE OF Challenge */
|
||||
/*-
|
||||
* popdecc [5] POPODecKeyChallContent, --pop Challenge
|
||||
*
|
||||
* POPODecKeyChallContent ::= SEQUENCE OF Challenge
|
||||
*/
|
||||
OSSL_CMP_POPODECKEYCHALLCONTENT *popdecc; /* 5 */
|
||||
/* popdecr [6] POPODecKeyRespContent, --pop Response */
|
||||
/* POPODecKeyRespContent ::= SEQUENCE OF INTEGER */
|
||||
/*-
|
||||
* popdecr [6] POPODecKeyRespContent, --pop Response
|
||||
*
|
||||
* POPODecKeyRespContent ::= SEQUENCE OF INTEGER
|
||||
*/
|
||||
OSSL_CMP_POPODECKEYRESPCONTENT *popdecr; /* 6 */
|
||||
OSSL_CRMF_MSGS *kur; /* 7 */
|
||||
OSSL_CMP_CERTREPMESSAGE *kup; /* 8 */
|
||||
OSSL_CRMF_MSGS *krr; /* 9 */
|
||||
|
||||
/* krp [10] KeyRecRepContent, --Key Recovery Response */
|
||||
/*-
|
||||
* krp [10] KeyRecRepContent, --Key Recovery Response
|
||||
*/
|
||||
OSSL_CMP_KEYRECREPCONTENT *krp; /* 10 */
|
||||
/* rr [11] RevReqContent, --Revocation Request */
|
||||
/*-
|
||||
* rr [11] RevReqContent, --Revocation Request
|
||||
*/
|
||||
OSSL_CMP_REVREQCONTENT *rr; /* 11 */
|
||||
/* rp [12] RevRepContent, --Revocation Response */
|
||||
/*-
|
||||
* rp [12] RevRepContent, --Revocation Response
|
||||
*/
|
||||
OSSL_CMP_REVREPCONTENT *rp; /* 12 */
|
||||
/* ccr [13] CertReqMessages, --Cross-Cert. Request */
|
||||
/*-
|
||||
* ccr [13] CertReqMessages, --Cross-Cert. Request
|
||||
*/
|
||||
OSSL_CRMF_MSGS *ccr; /* 13 */
|
||||
/* ccp [14] CertRepMessage, --Cross-Cert. Response */
|
||||
/*-
|
||||
* ccp [14] CertRepMessage, --Cross-Cert. Response
|
||||
*/
|
||||
OSSL_CMP_CERTREPMESSAGE *ccp; /* 14 */
|
||||
/* ckuann [15] CAKeyUpdAnnContent, --CA Key Update Ann. */
|
||||
/*-
|
||||
* ckuann [15] CAKeyUpdAnnContent, --CA Key Update Ann.
|
||||
*/
|
||||
OSSL_CMP_CAKEYUPDANNCONTENT *ckuann; /* 15 */
|
||||
/* cann [16] CertAnnContent, --Certificate Ann. */
|
||||
/* OSSL_CMP_CMPCERTIFICATE is effectively X509 so it is used directly */
|
||||
X509 *cann; /* 16 */
|
||||
/* rann [17] RevAnnContent, --Revocation Ann. */
|
||||
/*-
|
||||
* cann [16] CertAnnContent, --Certificate Ann.
|
||||
* OSSL_CMP_CMPCERTIFICATE is effectively X509 so it is used directly
|
||||
*/
|
||||
X509 *cann; /* 16 */
|
||||
/*-
|
||||
* rann [17] RevAnnContent, --Revocation Ann.
|
||||
*/
|
||||
OSSL_CMP_REVANNCONTENT *rann; /* 17 */
|
||||
/* crlann [18] CRLAnnContent, --CRL Announcement */
|
||||
/* CRLAnnContent ::= SEQUENCE OF CertificateList */
|
||||
OSSL_CMP_CRLANNCONTENT *crlann;
|
||||
/* PKIConfirmContent ::= NULL */
|
||||
/* pkiconf [19] PKIConfirmContent, --Confirmation */
|
||||
/* OSSL_CMP_PKICONFIRMCONTENT would be only a typedef of ASN1_NULL */
|
||||
/* OSSL_CMP_CONFIRMCONTENT *pkiconf; */
|
||||
/*
|
||||
/*-
|
||||
* crlann [18] CRLAnnContent, --CRL Announcement
|
||||
* CRLAnnContent ::= SEQUENCE OF CertificateList
|
||||
*/
|
||||
OSSL_CMP_CRLANNCONTENT *crlann; /* 18 */
|
||||
/*-
|
||||
* PKIConfirmContent ::= NULL
|
||||
* pkiconf [19] PKIConfirmContent, --Confirmation
|
||||
* OSSL_CMP_PKICONFIRMCONTENT would be only a typedef of ASN1_NULL
|
||||
* OSSL_CMP_CONFIRMCONTENT *pkiconf;
|
||||
*
|
||||
* NOTE: this should ASN1_NULL according to the RFC
|
||||
* but there might be a struct in it when sent from faulty servers...
|
||||
*/
|
||||
ASN1_TYPE *pkiconf; /* 19 */
|
||||
/* nested [20] NestedMessageContent, --Nested Message */
|
||||
/* NestedMessageContent ::= PKIMessages */
|
||||
/*-
|
||||
* nested [20] NestedMessageContent, --Nested Message
|
||||
* NestedMessageContent ::= PKIMessages
|
||||
*/
|
||||
OSSL_CMP_MSGS *nested; /* 20 */
|
||||
/* genm [21] GenMsgContent, --General Message */
|
||||
/* GenMsgContent ::= SEQUENCE OF InfoTypeAndValue */
|
||||
/*-
|
||||
* genm [21] GenMsgContent, --General Message
|
||||
* GenMsgContent ::= SEQUENCE OF InfoTypeAndValue
|
||||
*/
|
||||
OSSL_CMP_GENMSGCONTENT *genm; /* 21 */
|
||||
/* genp [22] GenRepContent, --General Response */
|
||||
/* GenRepContent ::= SEQUENCE OF InfoTypeAndValue */
|
||||
/*-
|
||||
* genp [22] GenRepContent, --General Response
|
||||
* GenRepContent ::= SEQUENCE OF InfoTypeAndValue
|
||||
*/
|
||||
OSSL_CMP_GENREPCONTENT *genp; /* 22 */
|
||||
/* error [23] ErrorMsgContent, --Error Message */
|
||||
/*-
|
||||
* error [23] ErrorMsgContent, --Error Message
|
||||
*/
|
||||
OSSL_CMP_ERRORMSGCONTENT *error; /* 23 */
|
||||
/* certConf [24] CertConfirmContent, --Certificate confirm */
|
||||
/*-
|
||||
* certConf [24] CertConfirmContent, --Certificate confirm
|
||||
*/
|
||||
OSSL_CMP_CERTCONFIRMCONTENT *certConf; /* 24 */
|
||||
/* pollReq [25] PollReqContent, --Polling request */
|
||||
OSSL_CMP_POLLREQCONTENT *pollReq;
|
||||
/* pollRep [26] PollRepContent --Polling response */
|
||||
OSSL_CMP_POLLREPCONTENT *pollRep;
|
||||
/*-
|
||||
* pollReq [25] PollReqContent, --Polling request
|
||||
*/
|
||||
OSSL_CMP_POLLREQCONTENT *pollReq; /* 25 */
|
||||
/*-
|
||||
* pollRep [26] PollRepContent --Polling response
|
||||
*/
|
||||
OSSL_CMP_POLLREPCONTENT *pollRep; /* 26 */
|
||||
} value;
|
||||
} OSSL_CMP_PKIBODY;
|
||||
DECLARE_ASN1_FUNCTIONS(OSSL_CMP_PKIBODY)
|
||||
@@ -699,18 +746,15 @@ int ossl_cmp_asn1_get_int(const ASN1_INTEGER *a);
|
||||
const char *ossl_cmp_log_parse_metadata(const char *buf,
|
||||
OSSL_CMP_severity *level, char **func,
|
||||
char **file, int *line);
|
||||
/* workaround for 4096 bytes limitation of ERR_print_errors_cb() */
|
||||
void ossl_cmp_add_error_txt(const char *separator, const char *txt);
|
||||
# define ossl_cmp_add_error_data(txt) ossl_cmp_add_error_txt(" : ", txt)
|
||||
# define ossl_cmp_add_error_line(txt) ossl_cmp_add_error_txt("\n", txt)
|
||||
# define ossl_cmp_add_error_data(txt) ERR_add_error_txt(" : ", txt)
|
||||
# define ossl_cmp_add_error_line(txt) ERR_add_error_txt("\n", txt)
|
||||
/* functions manipulating lists of certificates etc could be generally useful */
|
||||
int ossl_cmp_sk_X509_add1_cert (STACK_OF(X509) *sk, X509 *cert,
|
||||
int no_dup, int prepend);
|
||||
int ossl_cmp_sk_X509_add1_cert(STACK_OF(X509) *sk, X509 *cert,
|
||||
int no_dup, int prepend);
|
||||
int ossl_cmp_sk_X509_add1_certs(STACK_OF(X509) *sk, STACK_OF(X509) *certs,
|
||||
int no_self_signed, int no_dups, int prepend);
|
||||
int no_self_issued, int no_dups, int prepend);
|
||||
int ossl_cmp_X509_STORE_add1_certs(X509_STORE *store, STACK_OF(X509) *certs,
|
||||
int only_self_signed);
|
||||
STACK_OF(X509) *ossl_cmp_X509_STORE_get1_certs(X509_STORE *store);
|
||||
int only_self_issued);
|
||||
int ossl_cmp_asn1_octet_string_set1(ASN1_OCTET_STRING **tgt,
|
||||
const ASN1_OCTET_STRING *src);
|
||||
int ossl_cmp_asn1_octet_string_set1_bytes(ASN1_OCTET_STRING **tgt,
|
||||
@@ -718,6 +762,31 @@ int ossl_cmp_asn1_octet_string_set1_bytes(ASN1_OCTET_STRING **tgt,
|
||||
STACK_OF(X509) *ossl_cmp_build_cert_chain(STACK_OF(X509) *certs, X509 *cert);
|
||||
|
||||
/* from cmp_ctx.c */
|
||||
int ossl_cmp_print_log(OSSL_CMP_severity level, const OSSL_CMP_CTX *ctx,
|
||||
const char *func, const char *file, int line,
|
||||
const char *level_str, const char *format, ...);
|
||||
# define ossl_cmp_log(level, ctx, msg) \
|
||||
ossl_cmp_print_log(OSSL_CMP_LOG_##level, ctx, OPENSSL_FUNC, OPENSSL_FILE, \
|
||||
OPENSSL_LINE, #level, "%s", msg)
|
||||
# define ossl_cmp_log1(level, ctx, fmt, arg1) \
|
||||
ossl_cmp_print_log(OSSL_CMP_LOG_##level, ctx, OPENSSL_FUNC, OPENSSL_FILE, \
|
||||
OPENSSL_LINE, #level, fmt, arg1)
|
||||
# define ossl_cmp_log2(level, ctx, fmt, arg1, arg2) \
|
||||
ossl_cmp_print_log(OSSL_CMP_LOG_##level, ctx, OPENSSL_FUNC, OPENSSL_FILE, \
|
||||
OPENSSL_LINE, #level, fmt, arg1, arg2)
|
||||
# define ossl_cmp_log3(level, ctx, fmt, arg1, arg2, arg3) \
|
||||
ossl_cmp_print_log(OSSL_CMP_LOG_##level, ctx, OPENSSL_FUNC, OPENSSL_FILE, \
|
||||
OPENSSL_LINE, #level, fmt, arg1, arg2, arg3)
|
||||
# define ossl_cmp_log4(level, ctx, fmt, arg1, arg2, arg3, arg4) \
|
||||
ossl_cmp_print_log(OSSL_CMP_LOG_##level, ctx, OPENSSL_FUNC, OPENSSL_FILE, \
|
||||
OPENSSL_LINE, #level, fmt, arg1, arg2, arg3, arg4)
|
||||
# define OSSL_CMP_LOG_ERROR OSSL_CMP_LOG_ERR
|
||||
# define OSSL_CMP_LOG_WARN OSSL_CMP_LOG_WARNING
|
||||
# define ossl_cmp_alert(ctx, msg) ossl_cmp_log(ALERT, ctx, msg)
|
||||
# define ossl_cmp_err(ctx, msg) ossl_cmp_log(ERROR, ctx, msg)
|
||||
# define ossl_cmp_warn(ctx, msg) ossl_cmp_log(WARN, ctx, msg)
|
||||
# define ossl_cmp_info(ctx, msg) ossl_cmp_log(INFO, ctx, msg)
|
||||
# define ossl_cmp_debug(ctx, msg) ossl_cmp_log(DEBUG, ctx, msg)
|
||||
int ossl_cmp_ctx_set0_validatedSrvCert(OSSL_CMP_CTX *ctx, X509 *cert);
|
||||
int ossl_cmp_ctx_set_status(OSSL_CMP_CTX *ctx, int status);
|
||||
int ossl_cmp_ctx_set0_statusString(OSSL_CMP_CTX *ctx,
|
||||
@@ -825,7 +894,7 @@ OSSL_CMP_MSG *ossl_cmp_pollRep_new(OSSL_CMP_CTX *ctx, int crid,
|
||||
OSSL_CMP_PKISI *
|
||||
ossl_cmp_revrepcontent_get_pkistatusinfo(OSSL_CMP_REVREPCONTENT *rrep, int rsid);
|
||||
OSSL_CRMF_CERTID *ossl_cmp_revrepcontent_get_CertId(OSSL_CMP_REVREPCONTENT *rrep,
|
||||
int rsid);
|
||||
int rsid);
|
||||
OSSL_CMP_POLLREP *
|
||||
ossl_cmp_pollrepcontent_get0_pollrep(const OSSL_CMP_POLLREPCONTENT *prc,
|
||||
int rid);
|
||||
@@ -836,9 +905,9 @@ X509 *ossl_cmp_certresponse_get1_certificate(EVP_PKEY *privkey,
|
||||
const OSSL_CMP_CERTRESPONSE *crep);
|
||||
OSSL_CMP_MSG *ossl_cmp_msg_load(const char *file);
|
||||
/* BIO definitions */
|
||||
# define OSSL_d2i_CMP_MSG_bio(bp, p) \
|
||||
# define OSSL_d2i_CMP_MSG_bio(bp, p) \
|
||||
ASN1_d2i_bio_of(OSSL_CMP_MSG, OSSL_CMP_MSG_new, d2i_OSSL_CMP_MSG, bp, p)
|
||||
# define OSSL_i2d_CMP_MSG_bio(bp, o) \
|
||||
# define OSSL_i2d_CMP_MSG_bio(bp, o) \
|
||||
ASN1_i2d_bio_of(OSSL_CMP_MSG, i2d_OSSL_CMP_MSG, bp, o)
|
||||
|
||||
/* from cmp_protect.c */
|
||||
@@ -848,4 +917,12 @@ ASN1_BIT_STRING *ossl_cmp_calc_protection(const OSSL_CMP_MSG *msg,
|
||||
int ossl_cmp_msg_add_extraCerts(OSSL_CMP_CTX *ctx, OSSL_CMP_MSG *msg);
|
||||
int ossl_cmp_msg_protect(OSSL_CMP_CTX *ctx, OSSL_CMP_MSG *msg);
|
||||
|
||||
/* from cmp_vfy.c */
|
||||
typedef int (*ossl_cmp_allow_unprotected_cb_t)(const OSSL_CMP_CTX *ctx,
|
||||
const OSSL_CMP_MSG *msg,
|
||||
int invalid_protection, int arg);
|
||||
int ossl_cmp_msg_check_received(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg,
|
||||
ossl_cmp_allow_unprotected_cb_t cb, int cb_arg);
|
||||
int ossl_cmp_verify_popo(const OSSL_CMP_MSG *msg, int accept_RAVerified);
|
||||
|
||||
#endif /* !defined OSSL_CRYPTO_CMP_LOCAL_H */
|
||||
@@ -232,7 +232,7 @@ static OSSL_CRMF_MSG *crm_new(OSSL_CMP_CTX *ctx, int bodytype,
|
||||
*/
|
||||
|| !OSSL_CRMF_CERTTEMPLATE_fill(OSSL_CRMF_MSG_get0_tmpl(crm), rkey,
|
||||
subject, ctx->issuer,
|
||||
NULL/* serial */))
|
||||
NULL /* serial */))
|
||||
goto err;
|
||||
if (ctx->days != 0) {
|
||||
time_t notBefore, notAfter;
|
||||
@@ -442,8 +442,8 @@ OSSL_CMP_MSG *ossl_cmp_rr_new(OSSL_CMP_CTX *ctx)
|
||||
|
||||
/* Fill the template from the contents of the certificate to be revoked */
|
||||
if (!OSSL_CRMF_CERTTEMPLATE_fill(rd->certDetails,
|
||||
NULL/* pubkey would be redundant */,
|
||||
NULL/* subject would be redundant */,
|
||||
NULL /* pubkey would be redundant */,
|
||||
NULL /* subject would be redundant */,
|
||||
X509_get_issuer_name(ctx->oldCert),
|
||||
X509_get_serialNumber(ctx->oldCert)))
|
||||
goto err;
|
||||
@@ -569,7 +569,7 @@ int ossl_cmp_msg_gen_push1_ITAVs(OSSL_CMP_MSG *msg,
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < sk_OSSL_CMP_ITAV_num(itavs); i++) {
|
||||
if ((itav = OSSL_CMP_ITAV_dup(sk_OSSL_CMP_ITAV_value(itavs,i))) == NULL)
|
||||
if ((itav = OSSL_CMP_ITAV_dup(sk_OSSL_CMP_ITAV_value(itavs, i))) == NULL)
|
||||
return 0;
|
||||
if (!ossl_cmp_msg_gen_push0_ITAV(msg, itav)) {
|
||||
OSSL_CMP_ITAV_free(itav);
|
||||
@@ -643,8 +643,8 @@ OSSL_CMP_MSG *ossl_cmp_error_new(OSSL_CMP_CTX *ctx, OSSL_CMP_PKISI *si,
|
||||
}
|
||||
if (errorDetails != NULL)
|
||||
if ((msg->body->value.error->errorDetails =
|
||||
sk_ASN1_UTF8STRING_deep_copy(errorDetails, ASN1_STRING_dup,
|
||||
ASN1_STRING_free)) == NULL)
|
||||
sk_ASN1_UTF8STRING_deep_copy(errorDetails, ASN1_STRING_dup,
|
||||
ASN1_STRING_free)) == NULL)
|
||||
goto err;
|
||||
|
||||
if (!unprotected && !ossl_cmp_msg_protect(ctx, msg))
|
||||
|
||||
@@ -156,7 +156,7 @@ int ossl_cmp_msg_add_extraCerts(OSSL_CMP_CTX *ctx, OSSL_CMP_MSG *msg)
|
||||
STACK_OF(X509) *chain =
|
||||
ossl_cmp_build_cert_chain(ctx->untrusted_certs, ctx->clCert);
|
||||
int res = ossl_cmp_sk_X509_add1_certs(msg->extraCerts, chain,
|
||||
1 /* no self-signed */,
|
||||
1 /* no self-issued */,
|
||||
1 /* no duplicates */, 0);
|
||||
sk_X509_pop_free(chain, X509_free);
|
||||
if (res == 0)
|
||||
|
||||
@@ -61,7 +61,7 @@ const char *ossl_cmp_PKIStatus_to_string(int status)
|
||||
char buf[40];
|
||||
BIO_snprintf(buf, sizeof(buf), "PKIStatus: invalid=%d", status);
|
||||
CMPerr(0, CMP_R_ERROR_PARSING_PKISTATUS);
|
||||
ossl_cmp_add_error_data(buf);
|
||||
ERR_add_error_data(1, buf);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@@ -195,7 +195,7 @@ char *OSSL_CMP_CTX_snprint_PKIStatus(OSSL_CMP_CTX *ctx, char *buf,
|
||||
int printed_chars;
|
||||
int failinfo_found = 0;
|
||||
int n_status_strings;
|
||||
char* write_ptr = buf;
|
||||
char *write_ptr = buf;
|
||||
|
||||
#define ADVANCE_BUFFER \
|
||||
if (printed_chars < 0 || (size_t)printed_chars >= bufsize) \
|
||||
|
||||
+57
-142
@@ -69,7 +69,8 @@ static OSSL_CMP_severity parse_level(const char *level)
|
||||
}
|
||||
|
||||
const char *ossl_cmp_log_parse_metadata(const char *buf,
|
||||
OSSL_CMP_severity *level, char **func, char **file, int *line)
|
||||
OSSL_CMP_severity *level,
|
||||
char **func, char **file, int *line)
|
||||
{
|
||||
const char *p_func = buf;
|
||||
const char *p_file = buf == NULL ? NULL : strchr(buf, ':');
|
||||
@@ -106,129 +107,75 @@ const char *ossl_cmp_log_parse_metadata(const char *buf,
|
||||
return msg;
|
||||
}
|
||||
|
||||
|
||||
#define UNKNOWN_FUNC "(unknown function)" /* the default for OPENSSL_FUNC */
|
||||
/*
|
||||
* auxiliary function for incrementally reporting texts via the error queue
|
||||
* substitute fallback if component/function name is NULL or empty or contains
|
||||
* just pseudo-information "(unknown function)" due to -pedantic and macros.h
|
||||
*/
|
||||
static void put_error(int lib, const char *func, int reason,
|
||||
const char *file, int line)
|
||||
static const char *improve_location_name(const char *func, const char *fallback)
|
||||
{
|
||||
ERR_new();
|
||||
ERR_set_debug(file, line, func);
|
||||
ERR_set_error(lib, reason, NULL /* no data here, so fmt is NULL */);
|
||||
if (!ossl_assert(fallback != NULL))
|
||||
return NULL;
|
||||
return func == NULL || *func == '\0' || strcmp(func, UNKNOWN_FUNC) == 0
|
||||
? fallback : func;
|
||||
}
|
||||
|
||||
#define ERR_print_errors_cb_LIMIT 4096 /* size of char buf[] variable there */
|
||||
#define TYPICAL_MAX_OUTPUT_BEFORE_DATA 100
|
||||
#define MAX_DATA_LEN (ERR_print_errors_cb_LIMIT-TYPICAL_MAX_OUTPUT_BEFORE_DATA)
|
||||
void ossl_cmp_add_error_txt(const char *separator, const char *txt)
|
||||
int OSSL_CMP_print_to_bio(BIO *bio, const char *component, const char *file,
|
||||
int line, OSSL_CMP_severity level, const char *msg)
|
||||
{
|
||||
const char *file = NULL;
|
||||
int line;
|
||||
const char *func = NULL;
|
||||
const char *data = NULL;
|
||||
int flags;
|
||||
unsigned long err = ERR_peek_last_error();
|
||||
const char *level_string =
|
||||
level == OSSL_CMP_LOG_EMERG ? "EMERG" :
|
||||
level == OSSL_CMP_LOG_ALERT ? "ALERT" :
|
||||
level == OSSL_CMP_LOG_CRIT ? "CRIT" :
|
||||
level == OSSL_CMP_LOG_ERR ? "error" :
|
||||
level == OSSL_CMP_LOG_WARNING ? "warning" :
|
||||
level == OSSL_CMP_LOG_NOTICE ? "NOTE" :
|
||||
level == OSSL_CMP_LOG_INFO ? "info" :
|
||||
level == OSSL_CMP_LOG_DEBUG ? "DEBUG" : "(unknown level)";
|
||||
|
||||
if (separator == NULL)
|
||||
separator = "";
|
||||
if (err == 0)
|
||||
put_error(ERR_LIB_CMP, NULL, 0, "", 0);
|
||||
|
||||
do {
|
||||
size_t available_len, data_len;
|
||||
const char *curr = txt, *next = txt;
|
||||
char *tmp;
|
||||
|
||||
ERR_peek_last_error_all(&file, &line, &func, &data, &flags);
|
||||
if ((flags & ERR_TXT_STRING) == 0) {
|
||||
data = "";
|
||||
separator = "";
|
||||
}
|
||||
data_len = strlen(data);
|
||||
|
||||
/* workaround for limit of ERR_print_errors_cb() */
|
||||
if (data_len >= MAX_DATA_LEN
|
||||
|| strlen(separator) >= (size_t)(MAX_DATA_LEN - data_len))
|
||||
available_len = 0;
|
||||
else
|
||||
available_len = MAX_DATA_LEN - data_len - strlen(separator) - 1;
|
||||
/* MAX_DATA_LEN > available_len >= 0 */
|
||||
|
||||
if (separator[0] == '\0') {
|
||||
const size_t len_next = strlen(next);
|
||||
|
||||
if (len_next <= available_len) {
|
||||
next += len_next;
|
||||
curr = NULL; /* no need to split */
|
||||
}
|
||||
else {
|
||||
next += available_len;
|
||||
curr = next; /* will split at this point */
|
||||
}
|
||||
} else {
|
||||
while (*next != '\0' && (size_t)(next - txt) <= available_len) {
|
||||
curr = next;
|
||||
next = strstr(curr, separator);
|
||||
if (next != NULL)
|
||||
next += strlen(separator);
|
||||
else
|
||||
next = curr + strlen(curr);
|
||||
}
|
||||
if ((size_t)(next - txt) <= available_len)
|
||||
curr = NULL; /* the above loop implies *next == '\0' */
|
||||
}
|
||||
if (curr != NULL) {
|
||||
/* split error msg at curr since error data would get too long */
|
||||
if (curr != txt) {
|
||||
tmp = OPENSSL_strndup(txt, curr - txt);
|
||||
if (tmp == NULL)
|
||||
return;
|
||||
ERR_add_error_data(2, separator, tmp);
|
||||
OPENSSL_free(tmp);
|
||||
}
|
||||
put_error(ERR_LIB_CMP, func, err, file, line);
|
||||
txt = curr;
|
||||
} else {
|
||||
ERR_add_error_data(2, separator, txt);
|
||||
txt = next; /* finished */
|
||||
}
|
||||
} while (*txt != '\0');
|
||||
#ifndef NDEBUG
|
||||
if (BIO_printf(bio, "%s:%s:%d:", improve_location_name(component, "CMP"),
|
||||
file, line) < 0)
|
||||
return 0;
|
||||
#endif
|
||||
return BIO_printf(bio, OSSL_CMP_LOG_PREFIX"%s: %s\n",
|
||||
level_string, msg) >= 0;
|
||||
}
|
||||
|
||||
#define ERR_PRINT_BUF_SIZE 4096
|
||||
/* this is similar to ERR_print_errors_cb, but uses the CMP-specific cb type */
|
||||
void OSSL_CMP_print_errors_cb(OSSL_cmp_log_cb_t log_fn)
|
||||
{
|
||||
unsigned long err;
|
||||
char msg[ERR_print_errors_cb_LIMIT];
|
||||
char msg[ERR_PRINT_BUF_SIZE];
|
||||
const char *file = NULL, *func = NULL, *data = NULL;
|
||||
int line, flags;
|
||||
|
||||
if (log_fn == NULL) {
|
||||
#ifndef OPENSSL_NO_STDIO
|
||||
ERR_print_errors_fp(stderr);
|
||||
#else
|
||||
/* CMPerr(0, CMP_R_NO_STDIO) makes no sense during error printing */
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
while ((err = ERR_get_error_all(&file, &line, &func, &data, &flags)) != 0) {
|
||||
char component[128];
|
||||
const char *func_ = func != NULL && *func != '\0' ? func : "<unknown>";
|
||||
const char *component =
|
||||
improve_location_name(func, ERR_lib_error_string(err));
|
||||
|
||||
if (!(flags & ERR_TXT_STRING))
|
||||
data = NULL;
|
||||
#ifdef OSSL_CMP_PRINT_LIBINFO
|
||||
BIO_snprintf(component, sizeof(component), "OpenSSL:%s:%s",
|
||||
ERR_lib_error_string(err), func_);
|
||||
#else
|
||||
BIO_snprintf(component, sizeof(component), "%s",func_);
|
||||
#endif
|
||||
BIO_snprintf(msg, sizeof(msg), "%s%s%s", ERR_reason_error_string(err),
|
||||
data == NULL ? "" : " : ", data == NULL ? "" : data);
|
||||
if (log_fn(component, file, line, OSSL_CMP_LOG_ERR, msg) <= 0)
|
||||
break; /* abort outputting the error report */
|
||||
data == NULL || *data == '\0' ? "" : " : ",
|
||||
data == NULL ? "" : data);
|
||||
if (log_fn == NULL) {
|
||||
#ifndef OPENSSL_NO_STDIO
|
||||
BIO *bio = BIO_new_fp(stderr, BIO_NOCLOSE);
|
||||
|
||||
if (bio != NULL) {
|
||||
OSSL_CMP_print_to_bio(bio, component, file, line,
|
||||
OSSL_CMP_LOG_ERR, msg);
|
||||
BIO_free(bio);
|
||||
}
|
||||
#else
|
||||
/* CMPerr(0, CMP_R_NO_STDIO) makes no sense during error printing */
|
||||
#endif
|
||||
} else {
|
||||
if (log_fn(component, file, line, OSSL_CMP_LOG_ERR, msg) <= 0)
|
||||
break; /* abort outputting the error report */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,7 +213,7 @@ int ossl_cmp_sk_X509_add1_cert(STACK_OF(X509) *sk, X509 *cert,
|
||||
}
|
||||
|
||||
int ossl_cmp_sk_X509_add1_certs(STACK_OF(X509) *sk, STACK_OF(X509) *certs,
|
||||
int no_self_signed, int no_dups, int prepend)
|
||||
int no_self_issued, int no_dups, int prepend)
|
||||
/* compiler would allow 'const' for the list of certs, yet they are up-ref'ed */
|
||||
{
|
||||
int i;
|
||||
@@ -278,7 +225,7 @@ int ossl_cmp_sk_X509_add1_certs(STACK_OF(X509) *sk, STACK_OF(X509) *certs,
|
||||
for (i = 0; i < sk_X509_num(certs); i++) { /* certs may be NULL */
|
||||
X509 *cert = sk_X509_value(certs, i);
|
||||
|
||||
if (!no_self_signed || X509_check_issued(cert, cert) != X509_V_OK) {
|
||||
if (!no_self_issued || X509_check_issued(cert, cert) != X509_V_OK) {
|
||||
if (!ossl_cmp_sk_X509_add1_cert(sk, cert, no_dups, prepend))
|
||||
return 0;
|
||||
}
|
||||
@@ -287,7 +234,7 @@ int ossl_cmp_sk_X509_add1_certs(STACK_OF(X509) *sk, STACK_OF(X509) *certs,
|
||||
}
|
||||
|
||||
int ossl_cmp_X509_STORE_add1_certs(X509_STORE *store, STACK_OF(X509) *certs,
|
||||
int only_self_signed)
|
||||
int only_self_issued)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -300,45 +247,13 @@ int ossl_cmp_X509_STORE_add1_certs(X509_STORE *store, STACK_OF(X509) *certs,
|
||||
for (i = 0; i < sk_X509_num(certs); i++) {
|
||||
X509 *cert = sk_X509_value(certs, i);
|
||||
|
||||
if (!only_self_signed || X509_check_issued(cert, cert) == X509_V_OK)
|
||||
if (!only_self_issued || X509_check_issued(cert, cert) == X509_V_OK)
|
||||
if (!X509_STORE_add_cert(store, cert)) /* ups cert ref counter */
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
STACK_OF(X509) *ossl_cmp_X509_STORE_get1_certs(X509_STORE *store)
|
||||
{
|
||||
int i;
|
||||
STACK_OF(X509) *sk;
|
||||
STACK_OF(X509_OBJECT) *objs;
|
||||
|
||||
if (store == NULL) {
|
||||
CMPerr(0, CMP_R_NULL_ARGUMENT);
|
||||
return 0;
|
||||
}
|
||||
if ((sk = sk_X509_new_null()) == NULL)
|
||||
return NULL;
|
||||
objs = X509_STORE_get0_objects(store);
|
||||
for (i = 0; i < sk_X509_OBJECT_num(objs); i++) {
|
||||
X509 *cert = X509_OBJECT_get0_X509(sk_X509_OBJECT_value(objs, i));
|
||||
|
||||
if (cert != NULL) {
|
||||
if (!sk_X509_push(sk, cert))
|
||||
goto err;
|
||||
if (!X509_up_ref(cert)) {
|
||||
(void)sk_X509_pop(sk);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
}
|
||||
return sk;
|
||||
|
||||
err:
|
||||
sk_X509_pop_free(sk, X509_free);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*-
|
||||
* Builds up the certificate chain of certs as high up as possible using
|
||||
* the given list of certs containing all possible intermediate certificates and
|
||||
@@ -390,10 +305,10 @@ STACK_OF(X509) *ossl_cmp_build_cert_chain(STACK_OF(X509) *certs, X509 *cert)
|
||||
|
||||
chain = X509_STORE_CTX_get0_chain(csc);
|
||||
|
||||
/* result list to store the up_ref'ed not self-signed certificates */
|
||||
/* result list to store the up_ref'ed not self-issued certificates */
|
||||
if ((result = sk_X509_new_null()) == NULL)
|
||||
goto err;
|
||||
if (!ossl_cmp_sk_X509_add1_certs(result, chain, 1 /* no self-signed */,
|
||||
if (!ossl_cmp_sk_X509_add1_certs(result, chain, 1 /* no self-issued */,
|
||||
1 /* no duplicates */, 0)) {
|
||||
sk_X509_free(result);
|
||||
result = NULL;
|
||||
@@ -438,7 +353,7 @@ int ossl_cmp_asn1_octet_string_set1_bytes(ASN1_OCTET_STRING **tgt,
|
||||
return 0;
|
||||
}
|
||||
if (bytes != NULL) {
|
||||
if ((new = ASN1_OCTET_STRING_new()) == NULL
|
||||
if ((new = ASN1_OCTET_STRING_new()) == NULL
|
||||
|| !(ASN1_OCTET_STRING_set(new, bytes, len))) {
|
||||
ASN1_OCTET_STRING_free(new);
|
||||
return 0;
|
||||
|
||||
@@ -0,0 +1,754 @@
|
||||
/*
|
||||
* Copyright 2007-2020 The OpenSSL Project Authors. All Rights Reserved.
|
||||
* Copyright Nokia 2007-2020
|
||||
* Copyright Siemens AG 2015-2020
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/* CMP functions for PKIMessage checking */
|
||||
|
||||
#include "cmp_local.h"
|
||||
#include <openssl/cmp_util.h>
|
||||
|
||||
/* explicit #includes not strictly needed since implied by the above: */
|
||||
#include <openssl/asn1t.h>
|
||||
#include <openssl/cmp.h>
|
||||
#include <openssl/crmf.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/x509.h>
|
||||
#include "crypto/x509.h"
|
||||
|
||||
/*
|
||||
* Verify a message protected by signature according to section 5.1.3.3
|
||||
* (sha1+RSA/DSA or any other algorithm supported by OpenSSL).
|
||||
*
|
||||
* Returns 1 on successful validation and 0 otherwise.
|
||||
*/
|
||||
static int verify_signature(const OSSL_CMP_CTX *cmp_ctx,
|
||||
const OSSL_CMP_MSG *msg, X509 *cert)
|
||||
{
|
||||
EVP_MD_CTX *ctx = NULL;
|
||||
CMP_PROTECTEDPART prot_part;
|
||||
int digest_nid, pk_nid;
|
||||
const EVP_MD *digest = NULL;
|
||||
EVP_PKEY *pubkey = NULL;
|
||||
int len;
|
||||
size_t prot_part_der_len = 0;
|
||||
unsigned char *prot_part_der = NULL;
|
||||
BIO *bio = BIO_new(BIO_s_mem()); /* may be NULL */
|
||||
int res = 0;
|
||||
|
||||
if (!ossl_assert(cmp_ctx != NULL && msg != NULL && cert != NULL))
|
||||
return 0;
|
||||
|
||||
/* verify that keyUsage, if present, contains digitalSignature */
|
||||
if (!cmp_ctx->ignore_keyusage
|
||||
&& (X509_get_key_usage(cert) & X509v3_KU_DIGITAL_SIGNATURE) == 0) {
|
||||
CMPerr(0, CMP_R_MISSING_KEY_USAGE_DIGITALSIGNATURE);
|
||||
goto sig_err;
|
||||
}
|
||||
|
||||
pubkey = X509_get_pubkey(cert);
|
||||
if (pubkey == NULL) {
|
||||
CMPerr(0, CMP_R_FAILED_EXTRACTING_PUBKEY);
|
||||
goto sig_err;
|
||||
}
|
||||
|
||||
/* create the DER representation of protected part */
|
||||
prot_part.header = msg->header;
|
||||
prot_part.body = msg->body;
|
||||
|
||||
len = i2d_CMP_PROTECTEDPART(&prot_part, &prot_part_der);
|
||||
if (len < 0 || prot_part_der == NULL)
|
||||
goto end;
|
||||
prot_part_der_len = (size_t) len;
|
||||
|
||||
/* verify signature of protected part */
|
||||
if (!OBJ_find_sigid_algs(OBJ_obj2nid(msg->header->protectionAlg->algorithm),
|
||||
&digest_nid, &pk_nid)
|
||||
|| digest_nid == NID_undef || pk_nid == NID_undef
|
||||
|| (digest = EVP_get_digestbynid(digest_nid)) == NULL) {
|
||||
CMPerr(0, CMP_R_ALGORITHM_NOT_SUPPORTED);
|
||||
goto sig_err;
|
||||
}
|
||||
|
||||
/* check msg->header->protectionAlg is consistent with public key type */
|
||||
if (EVP_PKEY_type(pk_nid) != EVP_PKEY_base_id(pubkey)) {
|
||||
CMPerr(0, CMP_R_WRONG_ALGORITHM_OID);
|
||||
goto sig_err;
|
||||
}
|
||||
if ((ctx = EVP_MD_CTX_new()) == NULL)
|
||||
goto end;
|
||||
if (EVP_DigestVerifyInit(ctx, NULL, digest, NULL, pubkey)
|
||||
&& EVP_DigestVerify(ctx, msg->protection->data,
|
||||
msg->protection->length,
|
||||
prot_part_der, prot_part_der_len) == 1) {
|
||||
res = 1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
sig_err:
|
||||
res = x509_print_ex_brief(bio, cert, X509_FLAG_NO_EXTENSIONS);
|
||||
CMPerr(0, CMP_R_ERROR_VALIDATING_PROTECTION);
|
||||
if (res)
|
||||
ERR_add_error_mem_bio("\n", bio);
|
||||
res = 0;
|
||||
|
||||
end:
|
||||
EVP_MD_CTX_free(ctx);
|
||||
OPENSSL_free(prot_part_der);
|
||||
EVP_PKEY_free(pubkey);
|
||||
BIO_free(bio);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Verify a message protected with PBMAC */
|
||||
static int verify_PBMAC(const OSSL_CMP_MSG *msg,
|
||||
const ASN1_OCTET_STRING *secret)
|
||||
{
|
||||
ASN1_BIT_STRING *protection = NULL;
|
||||
int valid = 0;
|
||||
|
||||
/* generate expected protection for the message */
|
||||
if ((protection = ossl_cmp_calc_protection(msg, secret, NULL)) == NULL)
|
||||
return 0; /* failed to generate protection string! */
|
||||
|
||||
valid = msg->protection != NULL && msg->protection->length >= 0
|
||||
&& msg->protection->type == protection->type
|
||||
&& msg->protection->length == protection->length
|
||||
&& CRYPTO_memcmp(msg->protection->data, protection->data,
|
||||
protection->length) == 0;
|
||||
ASN1_BIT_STRING_free(protection);
|
||||
if (!valid)
|
||||
CMPerr(0, CMP_R_WRONG_PBM_VALUE);
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
/*
|
||||
* Attempt to validate certificate and path using any given store with trusted
|
||||
* certs (possibly including CRLs and a cert verification callback function)
|
||||
* and non-trusted intermediate certs from the given ctx.
|
||||
*
|
||||
* Returns 1 on successful validation and 0 otherwise.
|
||||
*/
|
||||
int OSSL_CMP_validate_cert_path(OSSL_CMP_CTX *ctx, X509_STORE *trusted_store,
|
||||
X509 *cert)
|
||||
{
|
||||
int valid = 0;
|
||||
X509_STORE_CTX *csc = NULL;
|
||||
int err;
|
||||
|
||||
if (ctx == NULL || cert == NULL) {
|
||||
CMPerr(0, CMP_R_NULL_ARGUMENT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (trusted_store == NULL) {
|
||||
CMPerr(0, CMP_R_MISSING_TRUST_STORE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((csc = X509_STORE_CTX_new()) == NULL
|
||||
|| !X509_STORE_CTX_init(csc, trusted_store,
|
||||
cert, ctx->untrusted_certs))
|
||||
goto err;
|
||||
|
||||
valid = X509_verify_cert(csc) > 0;
|
||||
|
||||
/* make sure suitable error is queued even if callback did not do */
|
||||
err = ERR_peek_last_error();
|
||||
if (!valid && ERR_GET_REASON(err) != CMP_R_POTENTIALLY_INVALID_CERTIFICATE)
|
||||
CMPerr(0, CMP_R_POTENTIALLY_INVALID_CERTIFICATE);
|
||||
|
||||
err:
|
||||
X509_STORE_CTX_free(csc);
|
||||
return valid;
|
||||
}
|
||||
|
||||
/* Return 0 if expect_name != NULL and there is no matching actual_name */
|
||||
static int check_name(OSSL_CMP_CTX *ctx,
|
||||
const char *actual_desc, const X509_NAME *actual_name,
|
||||
const char *expect_desc, const X509_NAME *expect_name)
|
||||
{
|
||||
char *str;
|
||||
|
||||
if (expect_name == NULL)
|
||||
return 1; /* no expectation, thus trivially fulfilled */
|
||||
|
||||
/* make sure that a matching name is there */
|
||||
if (actual_name == NULL) {
|
||||
ossl_cmp_log1(WARN, ctx, "missing %s", actual_desc);
|
||||
return 0;
|
||||
}
|
||||
if (X509_NAME_cmp(actual_name, expect_name) == 0)
|
||||
return 1;
|
||||
|
||||
if ((str = X509_NAME_oneline(actual_name, NULL, 0)) != NULL)
|
||||
ossl_cmp_log2(INFO, ctx, " actual name in %s = %s", actual_desc, str);
|
||||
OPENSSL_free(str);
|
||||
if ((str = X509_NAME_oneline(expect_name, NULL, 0)) != NULL)
|
||||
ossl_cmp_log2(INFO, ctx, " does not match %s = %s", expect_desc, str);
|
||||
OPENSSL_free(str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return 0 if skid != NULL and there is no matching subject key ID in cert */
|
||||
static int check_kid(OSSL_CMP_CTX *ctx,
|
||||
X509 *cert, const ASN1_OCTET_STRING *skid)
|
||||
{
|
||||
char *actual, *expect;
|
||||
const ASN1_OCTET_STRING *ckid = X509_get0_subject_key_id(cert);
|
||||
|
||||
if (skid == NULL)
|
||||
return 1; /* no expectation, thus trivially fulfilled */
|
||||
|
||||
/* make sure that the expected subject key identifier is there */
|
||||
if (ckid == NULL) {
|
||||
ossl_cmp_warn(ctx, "missing Subject Key Identifier in certificate");
|
||||
return 0;
|
||||
}
|
||||
if (ASN1_OCTET_STRING_cmp(ckid, skid) == 0)
|
||||
return 1;
|
||||
|
||||
if ((actual = OPENSSL_buf2hexstr(ckid->data, ckid->length)) != NULL)
|
||||
ossl_cmp_log1(INFO, ctx, " cert Subject Key Identifier = %s", actual);
|
||||
if ((expect = OPENSSL_buf2hexstr(skid->data, skid->length)) != NULL)
|
||||
ossl_cmp_log1(INFO, ctx, " does not match senderKID = %s", expect);
|
||||
OPENSSL_free(expect);
|
||||
OPENSSL_free(actual);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int already_checked(X509 *cert, const STACK_OF(X509) *already_checked)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = sk_X509_num(already_checked /* may be NULL */); i > 0; i--)
|
||||
if (X509_cmp(sk_X509_value(already_checked, i - 1), cert) == 0)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the given cert is acceptable as sender cert of the given message.
|
||||
* The subject DN must match, the subject key ID as well if present in the msg,
|
||||
* and the cert must be current (checked if ctx->trusted is not NULL).
|
||||
* Note that cert revocation etc. is checked by OSSL_CMP_validate_cert_path().
|
||||
*
|
||||
* Returns 0 on error or not acceptable, else 1.
|
||||
*/
|
||||
static int cert_acceptable(OSSL_CMP_CTX *ctx,
|
||||
const char *desc1, const char *desc2, X509 *cert,
|
||||
const STACK_OF(X509) *already_checked1,
|
||||
const STACK_OF(X509) *already_checked2,
|
||||
const OSSL_CMP_MSG *msg)
|
||||
{
|
||||
X509_STORE *ts = ctx->trusted;
|
||||
char *sub, *iss;
|
||||
X509_VERIFY_PARAM *vpm = ts != NULL ? X509_STORE_get0_param(ts) : NULL;
|
||||
int time_cmp;
|
||||
|
||||
ossl_cmp_log2(INFO, ctx, " considering %s %s with..", desc1, desc2);
|
||||
if ((sub = X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0)) != NULL)
|
||||
ossl_cmp_log1(INFO, ctx, " subject = %s", sub);
|
||||
if ((iss = X509_NAME_oneline(X509_get_issuer_name(cert), NULL, 0)) != NULL)
|
||||
ossl_cmp_log1(INFO, ctx, " issuer = %s", iss);
|
||||
OPENSSL_free(iss);
|
||||
OPENSSL_free(sub);
|
||||
|
||||
if (already_checked(cert, already_checked1)
|
||||
|| already_checked(cert, already_checked2)) {
|
||||
ossl_cmp_info(ctx, " cert has already been checked");
|
||||
return 0;
|
||||
}
|
||||
|
||||
time_cmp = X509_cmp_timeframe(vpm, X509_get0_notBefore(cert),
|
||||
X509_get0_notAfter(cert));
|
||||
if (time_cmp != 0) {
|
||||
ossl_cmp_warn(ctx, time_cmp > 0 ? "cert has expired"
|
||||
: "cert is not yet valid");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!check_name(ctx,
|
||||
"cert subject", X509_get_subject_name(cert),
|
||||
"sender field", msg->header->sender->d.directoryName))
|
||||
return 0;
|
||||
|
||||
if (!check_kid(ctx, cert, msg->header->senderKID))
|
||||
return 0;
|
||||
/* acceptable also if there is no senderKID in msg header */
|
||||
ossl_cmp_info(ctx, " cert is acceptable");
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int check_msg_valid_cert(OSSL_CMP_CTX *ctx, X509_STORE *store,
|
||||
X509 *scrt, const OSSL_CMP_MSG *msg)
|
||||
{
|
||||
if (!verify_signature(ctx, msg, scrt)) {
|
||||
ossl_cmp_warn(ctx, "msg signature verification failed");
|
||||
return 0;
|
||||
}
|
||||
if (!OSSL_CMP_validate_cert_path(ctx, store, scrt)) {
|
||||
ossl_cmp_warn(ctx, "cert path validation failed");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Exceptional handling for 3GPP TS 33.310 [3G/LTE Network Domain Security
|
||||
* (NDS); Authentication Framework (AF)], only to use for IP and if the ctx
|
||||
* option is explicitly set: use self-issued certificates from extraCerts as
|
||||
* trust anchor to validate sender cert and msg -
|
||||
* provided it also can validate the newly enrolled certificate
|
||||
*/
|
||||
static int check_msg_valid_cert_3gpp(OSSL_CMP_CTX *ctx, X509 *scrt,
|
||||
const OSSL_CMP_MSG *msg)
|
||||
{
|
||||
int valid = 0;
|
||||
X509_STORE *store = X509_STORE_new();
|
||||
|
||||
if (store != NULL /* store does not include CRLs */
|
||||
&& ossl_cmp_X509_STORE_add1_certs(store, msg->extraCerts,
|
||||
1 /* self-issued only */))
|
||||
valid = check_msg_valid_cert(ctx, store, scrt, msg);
|
||||
if (valid) {
|
||||
/*
|
||||
* verify that the newly enrolled certificate (which is assumed to have
|
||||
* rid == 0) can also be validated with the same trusted store
|
||||
*/
|
||||
EVP_PKEY *privkey = OSSL_CMP_CTX_get0_newPkey(ctx, 1);
|
||||
OSSL_CMP_CERTRESPONSE *crep =
|
||||
ossl_cmp_certrepmessage_get0_certresponse(msg->body->value.ip, 0);
|
||||
X509 *newcrt = ossl_cmp_certresponse_get1_certificate(privkey, crep);
|
||||
/*
|
||||
* maybe better use get_cert_status() from cmp_client.c, which catches
|
||||
* errors
|
||||
*/
|
||||
valid = OSSL_CMP_validate_cert_path(ctx, store, newcrt);
|
||||
X509_free(newcrt);
|
||||
}
|
||||
X509_STORE_free(store);
|
||||
return valid;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try all certs in given list for verifying msg, normally or in 3GPP mode.
|
||||
* If already_checked1 == NULL then certs are assumed to be the msg->extraCerts.
|
||||
*/
|
||||
static int check_msg_with_certs(OSSL_CMP_CTX *ctx, STACK_OF(X509) *certs,
|
||||
const char *desc,
|
||||
const STACK_OF(X509) *already_checked1,
|
||||
const STACK_OF(X509) *already_checked2,
|
||||
const OSSL_CMP_MSG *msg, int mode_3gpp)
|
||||
{
|
||||
int in_extraCerts = already_checked1 == NULL;
|
||||
int n_acceptable_certs = 0;
|
||||
int i;
|
||||
|
||||
if (sk_X509_num(certs) <= 0) {
|
||||
ossl_cmp_log1(WARN, ctx, "no %s", desc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < sk_X509_num(certs); i++) { /* certs may be NULL */
|
||||
X509 *cert = sk_X509_value(certs, i);
|
||||
|
||||
if (!ossl_assert(cert != NULL))
|
||||
return 0;
|
||||
if (!cert_acceptable(ctx, "cert from", desc, cert,
|
||||
already_checked1, already_checked2, msg))
|
||||
continue;
|
||||
n_acceptable_certs++;
|
||||
if (mode_3gpp ? check_msg_valid_cert_3gpp(ctx, cert, msg)
|
||||
: check_msg_valid_cert(ctx, ctx->trusted, cert, msg)) {
|
||||
/* store successful sender cert for further msgs in transaction */
|
||||
if (!X509_up_ref(cert))
|
||||
return 0;
|
||||
if (!ossl_cmp_ctx_set0_validatedSrvCert(ctx, cert)) {
|
||||
X509_free(cert);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (in_extraCerts && n_acceptable_certs == 0)
|
||||
ossl_cmp_warn(ctx, "no acceptable cert in extraCerts");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify msg trying first ctx->untrusted_certs, which should include extraCerts
|
||||
* at its front, then trying the trusted certs in truststore (if any) of ctx.
|
||||
*/
|
||||
static int check_msg_all_certs(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg,
|
||||
int mode_3gpp)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ossl_cmp_info(ctx,
|
||||
mode_3gpp ? "failed; trying now 3GPP mode trusting extraCerts"
|
||||
: "trying first normal mode using trust store");
|
||||
if (check_msg_with_certs(ctx, msg->extraCerts, "extraCerts",
|
||||
NULL, NULL, msg, mode_3gpp))
|
||||
return 1;
|
||||
if (check_msg_with_certs(ctx, ctx->untrusted_certs, "untrusted certs",
|
||||
msg->extraCerts, NULL, msg, mode_3gpp))
|
||||
return 1;
|
||||
|
||||
if (ctx->trusted == NULL) {
|
||||
ossl_cmp_warn(ctx, mode_3gpp ? "no self-issued extraCerts"
|
||||
: "no trusted store");
|
||||
} else {
|
||||
STACK_OF(X509) *trusted = X509_STORE_get1_all_certs(ctx->trusted);
|
||||
ret = check_msg_with_certs(ctx, trusted,
|
||||
mode_3gpp ? "self-issued extraCerts"
|
||||
: "certs in trusted store",
|
||||
msg->extraCerts, ctx->untrusted_certs,
|
||||
msg, mode_3gpp);
|
||||
sk_X509_pop_free(trusted, X509_free);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* verify message signature with any acceptable and valid candidate cert */
|
||||
static int check_msg_find_cert(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg)
|
||||
{
|
||||
X509 *scrt = ctx->validatedSrvCert; /* previous successful sender cert */
|
||||
GENERAL_NAME *sender = msg->header->sender;
|
||||
char *sname = NULL;
|
||||
char *skid_str = NULL;
|
||||
const ASN1_OCTET_STRING *skid = msg->header->senderKID;
|
||||
OSSL_cmp_log_cb_t backup_log_cb = ctx->log_cb;
|
||||
int res = 0;
|
||||
|
||||
if (sender == NULL || msg->body == NULL)
|
||||
return 0; /* other NULL cases already have been checked */
|
||||
if (sender->type != GEN_DIRNAME) {
|
||||
CMPerr(0, CMP_R_SENDER_GENERALNAME_TYPE_NOT_SUPPORTED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* try first cached scrt, used successfully earlier in same transaction,
|
||||
* for validating this and any further msgs where extraCerts may be left out
|
||||
*/
|
||||
(void)ERR_set_mark();
|
||||
if (scrt != NULL
|
||||
&& cert_acceptable(ctx, "previously validated", "sender cert", scrt,
|
||||
NULL, NULL, msg)
|
||||
&& (check_msg_valid_cert(ctx, ctx->trusted, scrt, msg)
|
||||
|| check_msg_valid_cert_3gpp(ctx, scrt, msg))) {
|
||||
(void)ERR_pop_to_mark();
|
||||
return 1;
|
||||
}
|
||||
(void)ERR_pop_to_mark();
|
||||
|
||||
/* release any cached sender cert that proved no more successfully usable */
|
||||
(void)ossl_cmp_ctx_set0_validatedSrvCert(ctx, NULL);
|
||||
|
||||
/* enable clearing irrelevant errors in attempts to validate sender certs */
|
||||
(void)ERR_set_mark();
|
||||
ctx->log_cb = NULL; /* temporarily disable logging diagnostic info */
|
||||
|
||||
if (check_msg_all_certs(ctx, msg, 0 /* using ctx->trusted */)
|
||||
|| check_msg_all_certs(ctx, msg, 1 /* 3gpp */)) {
|
||||
/* discard any diagnostic info on trying to use certs */
|
||||
ctx->log_cb = backup_log_cb; /* restore any logging */
|
||||
(void)ERR_pop_to_mark();
|
||||
res = 1;
|
||||
goto end;
|
||||
}
|
||||
/* failed finding a sender cert that verifies the message signature */
|
||||
ctx->log_cb = backup_log_cb; /* restore any logging */
|
||||
(void)ERR_clear_last_mark();
|
||||
|
||||
sname = X509_NAME_oneline(sender->d.directoryName, NULL, 0);
|
||||
skid_str = skid == NULL ? NULL
|
||||
: OPENSSL_buf2hexstr(skid->data, skid->length);
|
||||
if (ctx->log_cb != NULL) {
|
||||
ossl_cmp_info(ctx, "verifying msg signature with valid cert that..");
|
||||
if (sname != NULL)
|
||||
ossl_cmp_log1(INFO, ctx, "matches msg sender name = %s", sname);
|
||||
if (skid_str != NULL)
|
||||
ossl_cmp_log1(INFO, ctx, "matches msg senderKID = %s", skid_str);
|
||||
else
|
||||
ossl_cmp_info(ctx, "while msg header does not contain senderKID");
|
||||
/* re-do the above checks (just) for adding diagnostic information */
|
||||
check_msg_all_certs(ctx, msg, 0 /* using ctx->trusted */);
|
||||
check_msg_all_certs(ctx, msg, 1 /* 3gpp */);
|
||||
}
|
||||
|
||||
CMPerr(0, CMP_R_NO_SUITABLE_SENDER_CERT);
|
||||
if (sname != NULL) {
|
||||
ERR_add_error_txt(NULL, "for msg sender name = ");
|
||||
ERR_add_error_txt(NULL, sname);
|
||||
}
|
||||
if (skid_str != NULL) {
|
||||
ERR_add_error_txt(" and ", "for msg senderKID = ");
|
||||
ERR_add_error_txt(NULL, skid_str);
|
||||
}
|
||||
|
||||
end:
|
||||
OPENSSL_free(sname);
|
||||
OPENSSL_free(skid_str);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate the protection of the given PKIMessage using either password-
|
||||
* based mac (PBM) or a signature algorithm. In the case of signature algorithm,
|
||||
* the sender certificate can have been pinned by providing it in ctx->srvCert,
|
||||
* else it is searched in msg->extraCerts, ctx->untrusted_certs, in ctx->trusted
|
||||
* (in this order) and is path is validated against ctx->trusted.
|
||||
*
|
||||
* If ctx->permitTAInExtraCertsForIR is true and when validating a CMP IP msg,
|
||||
* the trust anchor for validating the IP msg may be taken from msg->extraCerts
|
||||
* if a self-issued certificate is found there that can be used to
|
||||
* validate the enrolled certificate returned in the IP.
|
||||
* This is according to the need given in 3GPP TS 33.310.
|
||||
*
|
||||
* Returns 1 on success, 0 on error or validation failed.
|
||||
*/
|
||||
int OSSL_CMP_validate_msg(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg)
|
||||
{
|
||||
X509_ALGOR *alg;
|
||||
int nid = NID_undef, pk_nid = NID_undef;
|
||||
const ASN1_OBJECT *algorOID = NULL;
|
||||
X509 *scrt;
|
||||
|
||||
if (ctx == NULL || msg == NULL
|
||||
|| msg->header == NULL || msg->body == NULL) {
|
||||
CMPerr(0, CMP_R_NULL_ARGUMENT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((alg = msg->header->protectionAlg) == NULL /* unprotected message */
|
||||
|| msg->protection == NULL || msg->protection->data == NULL) {
|
||||
CMPerr(0, CMP_R_MISSING_PROTECTION);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* determine the nid for the used protection algorithm */
|
||||
X509_ALGOR_get0(&algorOID, NULL, NULL, alg);
|
||||
nid = OBJ_obj2nid(algorOID);
|
||||
|
||||
switch (nid) {
|
||||
/* 5.1.3.1. Shared Secret Information */
|
||||
case NID_id_PasswordBasedMAC:
|
||||
if (verify_PBMAC(msg, ctx->secretValue)) {
|
||||
/*
|
||||
* RFC 4210, 5.3.2: 'Note that if the PKI Message Protection is
|
||||
* "shared secret information", then any certificate transported in
|
||||
* the caPubs field may be directly trusted as a root CA
|
||||
* certificate by the initiator.'
|
||||
*/
|
||||
switch (ossl_cmp_msg_get_bodytype(msg)) {
|
||||
case -1:
|
||||
return 0;
|
||||
case OSSL_CMP_PKIBODY_IP:
|
||||
case OSSL_CMP_PKIBODY_CP:
|
||||
case OSSL_CMP_PKIBODY_KUP:
|
||||
case OSSL_CMP_PKIBODY_CCP:
|
||||
if (ctx->trusted != NULL) {
|
||||
STACK_OF(X509) *certs = msg->body->value.ip->caPubs;
|
||||
/* value.ip is same for cp, kup, and ccp */
|
||||
|
||||
if (!ossl_cmp_X509_STORE_add1_certs(ctx->trusted, certs, 0))
|
||||
/* adds both self-issued and not self-issued certs */
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
||||
/*
|
||||
* 5.1.3.2 DH Key Pairs
|
||||
* Not yet supported
|
||||
*/
|
||||
case NID_id_DHBasedMac:
|
||||
CMPerr(0, CMP_R_UNSUPPORTED_PROTECTION_ALG_DHBASEDMAC);
|
||||
break;
|
||||
|
||||
/*
|
||||
* 5.1.3.3. Signature
|
||||
*/
|
||||
default:
|
||||
if (!OBJ_find_sigid_algs(OBJ_obj2nid(alg->algorithm), NULL, &pk_nid)
|
||||
|| pk_nid == NID_undef) {
|
||||
CMPerr(0, CMP_R_UNKNOWN_ALGORITHM_ID);
|
||||
break;
|
||||
}
|
||||
/* validate sender name of received msg */
|
||||
if (msg->header->sender->type != GEN_DIRNAME) {
|
||||
CMPerr(0, CMP_R_SENDER_GENERALNAME_TYPE_NOT_SUPPORTED);
|
||||
break; /* FR#42: support for more than X509_NAME */
|
||||
}
|
||||
/*
|
||||
* Compare actual sender name of response with expected sender name.
|
||||
* Expected name can be set explicitly or the subject of ctx->srvCert.
|
||||
* Mitigates risk to accept misused certificate of an unauthorized
|
||||
* entity of a trusted hierarchy.
|
||||
*/
|
||||
if (!check_name(ctx, "sender DN field",
|
||||
msg->header->sender->d.directoryName,
|
||||
"expected sender", ctx->expected_sender))
|
||||
break;
|
||||
/* Note: if recipient was NULL-DN it could be learned here if needed */
|
||||
|
||||
scrt = ctx->srvCert;
|
||||
if (scrt == NULL) {
|
||||
if (check_msg_find_cert(ctx, msg))
|
||||
return 1;
|
||||
} else { /* use pinned sender cert */
|
||||
/* use ctx->srvCert for signature check even if not acceptable */
|
||||
if (verify_signature(ctx, msg, scrt))
|
||||
return 1;
|
||||
/* call cert_acceptable() for adding diagnostic information */
|
||||
(void)cert_acceptable(ctx, "explicitly set", "sender cert", scrt,
|
||||
NULL, NULL, msg);
|
||||
ossl_cmp_warn(ctx, "msg signature verification failed");
|
||||
CMPerr(0, CMP_R_SRVCERT_DOES_NOT_VALIDATE_MSG);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*-
|
||||
* Check received message (i.e., response by server or request from client)
|
||||
* Any msg->extraCerts are prepended to ctx->untrusted_certs
|
||||
*
|
||||
* Ensures that:
|
||||
* it has a valid body type
|
||||
* its protection is valid or absent (allowed only if callback function is
|
||||
* present and function yields non-zero result using also supplied argument)
|
||||
* its transaction ID matches the previous transaction ID stored in ctx (if any)
|
||||
* its recipNonce matches the previous senderNonce stored in the ctx (if any)
|
||||
*
|
||||
* If everything is fine:
|
||||
* learns the senderNonce from the received message,
|
||||
* learns the transaction ID if it is not yet in ctx.
|
||||
*
|
||||
* returns body type (which is >= 0) of the message on success, -1 on error
|
||||
*/
|
||||
int ossl_cmp_msg_check_received(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg,
|
||||
ossl_cmp_allow_unprotected_cb_t cb, int cb_arg)
|
||||
{
|
||||
int rcvd_type;
|
||||
|
||||
if (!ossl_assert(ctx != NULL && msg != NULL))
|
||||
return -1;
|
||||
|
||||
if (sk_X509_num(msg->extraCerts) > 10)
|
||||
ossl_cmp_warn(ctx,
|
||||
"received CMP message contains more than 10 extraCerts");
|
||||
|
||||
/* validate message protection */
|
||||
if (msg->header->protectionAlg != 0) {
|
||||
/* detect explicitly permitted exceptions for invalid protection */
|
||||
if (!OSSL_CMP_validate_msg(ctx, msg)
|
||||
&& (cb == NULL || !(*cb)(ctx, msg, 1, cb_arg))) {
|
||||
CMPerr(0, CMP_R_ERROR_VALIDATING_PROTECTION);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
/* detect explicitly permitted exceptions for missing protection */
|
||||
if (cb == NULL || !(*cb)(ctx, msg, 0, cb_arg)) {
|
||||
CMPerr(0, CMP_R_MISSING_PROTECTION);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Store any provided extraCerts in ctx for future use,
|
||||
* such that they are available to ctx->certConf_cb and
|
||||
* the peer does not need to send them again in the same transaction.
|
||||
* For efficiency, the extraCerts are prepended so they get used first.
|
||||
*/
|
||||
if (!ossl_cmp_sk_X509_add1_certs(ctx->untrusted_certs, msg->extraCerts,
|
||||
0 /* this allows self-issued certs */,
|
||||
1 /* no_dups */, 1 /* prepend */))
|
||||
return -1;
|
||||
|
||||
/* check CMP version number in header */
|
||||
if (ossl_cmp_hdr_get_pvno(OSSL_CMP_MSG_get0_header(msg)) != OSSL_CMP_PVNO) {
|
||||
CMPerr(0, CMP_R_UNEXPECTED_PVNO);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* compare received transactionID with the expected one in previous msg */
|
||||
if (ctx->transactionID != NULL
|
||||
&& (msg->header->transactionID == NULL
|
||||
|| ASN1_OCTET_STRING_cmp(ctx->transactionID,
|
||||
msg->header->transactionID) != 0)) {
|
||||
CMPerr(0, CMP_R_TRANSACTIONID_UNMATCHED);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* compare received nonce with the one we sent */
|
||||
if (ctx->senderNonce != NULL
|
||||
&& (msg->header->recipNonce == NULL
|
||||
|| ASN1_OCTET_STRING_cmp(ctx->senderNonce,
|
||||
msg->header->recipNonce) != 0)) {
|
||||
CMPerr(0, CMP_R_RECIPNONCE_UNMATCHED);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* RFC 4210 section 5.1.1 states: the recipNonce is copied from
|
||||
* the senderNonce of the previous message in the transaction.
|
||||
* --> Store for setting in next message
|
||||
*/
|
||||
if (!ossl_cmp_ctx_set1_recipNonce(ctx, msg->header->senderNonce))
|
||||
return -1;
|
||||
|
||||
/* if not yet present, learn transactionID */
|
||||
if (ctx->transactionID == NULL
|
||||
&& !OSSL_CMP_CTX_set1_transactionID(ctx, msg->header->transactionID))
|
||||
return -1;
|
||||
|
||||
if ((rcvd_type = ossl_cmp_msg_get_bodytype(msg)) < 0) {
|
||||
CMPerr(0, CMP_R_PKIBODY_ERROR);
|
||||
return -1;
|
||||
}
|
||||
return rcvd_type;
|
||||
}
|
||||
|
||||
int ossl_cmp_verify_popo(const OSSL_CMP_MSG *msg, int accept_RAVerified)
|
||||
{
|
||||
if (!ossl_assert(msg != NULL && msg->body != NULL))
|
||||
return 0;
|
||||
switch (msg->body->type) {
|
||||
case OSSL_CMP_PKIBODY_P10CR:
|
||||
{
|
||||
X509_REQ *req = msg->body->value.p10cr;
|
||||
|
||||
if (X509_REQ_verify(req, X509_REQ_get0_pubkey(req)) > 0)
|
||||
return 1;
|
||||
CMPerr(0, CMP_R_REQUEST_NOT_ACCEPTED);
|
||||
return 0;
|
||||
}
|
||||
case OSSL_CMP_PKIBODY_IR:
|
||||
case OSSL_CMP_PKIBODY_CR:
|
||||
case OSSL_CMP_PKIBODY_KUR:
|
||||
return OSSL_CRMF_MSGS_verify_popo(msg->body->value.ir,
|
||||
OSSL_CMP_CERTREQID,
|
||||
accept_RAVerified);
|
||||
default:
|
||||
CMPerr(0, CMP_R_PKIBODY_ERROR);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user