/* * Copyright 2007-2022 The OpenSSL Project Authors. All Rights Reserved. * Copyright Nokia 2007-2019 * Copyright Siemens AG 2015-2019 * * 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 PKIHeader handling */ #include "cmp_local.h" #include /* explicit #includes not strictly needed since implied by the above: */ #include #include #include int ossl_cmp_hdr_set_pvno(OSSL_CMP_PKIHEADER *hdr, int pvno) { if (!ossl_assert(hdr != NULL)) return 0; return ASN1_INTEGER_set(hdr->pvno, pvno); } int ossl_cmp_hdr_get_pvno(const OSSL_CMP_PKIHEADER *hdr) { int64_t pvno; if (!ossl_assert(hdr != NULL)) return -1; if (!ASN1_INTEGER_get_int64(&pvno, hdr->pvno) || pvno < 0 || pvno > INT_MAX) return -1; return (int)pvno; } int ossl_cmp_hdr_get_protection_nid(const OSSL_CMP_PKIHEADER *hdr) { if (!ossl_assert(hdr != NULL) || hdr->protectionAlg == NULL) return NID_undef; return OBJ_obj2nid(hdr->protectionAlg->algorithm); } ASN1_OCTET_STRING *OSSL_CMP_HDR_get0_transactionID(const OSSL_CMP_PKIHEADER *hdr) { if (hdr == NULL) { ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); return NULL; } return hdr->transactionID; } ASN1_OCTET_STRING *ossl_cmp_hdr_get0_senderNonce(const OSSL_CMP_PKIHEADER *hdr) { if (!ossl_assert(hdr != NULL)) return NULL; return hdr->senderNonce; } ASN1_OCTET_STRING *OSSL_CMP_HDR_get0_recipNonce(const OSSL_CMP_PKIHEADER *hdr) { if (hdr == NULL) { ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); return NULL; } return hdr->recipNonce; } /* a NULL-DN as an empty sequence of RDNs */ int ossl_cmp_general_name_is_NULL_DN(GENERAL_NAME *name) { return name == NULL || (name->type == GEN_DIRNAME && IS_NULL_DN(name->d.directoryName)); } /* assign to *tgt a copy of src (which may be NULL to indicate an empty DN) */ static int set1_general_name(GENERAL_NAME **tgt, const X509_NAME *src) { GENERAL_NAME *name; if (!ossl_assert(tgt != NULL)) return 0; if ((name = GENERAL_NAME_new()) == NULL) goto err; name->type = GEN_DIRNAME; if (src == NULL) { /* NULL-DN */ if ((name->d.directoryName = X509_NAME_new()) == NULL) goto err; } else if (!X509_NAME_set(&name->d.directoryName, src)) { goto err; } GENERAL_NAME_free(*tgt); *tgt = name; return 1; err: GENERAL_NAME_free(name); return 0; } /* * Set the sender name in PKIHeader. * when nm is NULL, sender is set to an empty string * returns 1 on success, 0 on error */ int ossl_cmp_hdr_set1_sender(OSSL_CMP_PKIHEADER *hdr, const X509_NAME *nm) { if (!ossl_assert(hdr != NULL)) return 0; return set1_general_name(&hdr->sender, nm); } int ossl_cmp_hdr_set1_recipient(OSSL_CMP_PKIHEADER *hdr, const X509_NAME *nm) { if (!ossl_assert(hdr != NULL)) return 0; return set1_general_name(&hdr->recipient, nm); } int ossl_cmp_hdr_update_messageTime(OSSL_CMP_PKIHEADER *hdr) { if (!ossl_assert(hdr != NULL)) return 0; if (hdr->messageTime == NULL && (hdr->messageTime = ASN1_GENERALIZEDTIME_new()) == NULL) return 0; return ASN1_GENERALIZEDTIME_set(hdr->messageTime, time(NULL)) != NULL; } /* assign to *tgt a random byte array of given length */ static int set_random(ASN1_OCTET_STRING **tgt, OSSL_CMP_CTX *ctx, size_t len) { unsigned char *bytes = OPENSSL_malloc(len); int res = 0; if (bytes == NULL || RAND_bytes_ex(ctx->libctx, bytes, len, 0) <= 0) ERR_raise(ERR_LIB_CMP, CMP_R_FAILURE_OBTAINING_RANDOM); else res = ossl_cmp_asn1_octet_string_set1_bytes(tgt, bytes, len); OPENSSL_free(bytes); return res; } int ossl_cmp_hdr_set1_senderKID(OSSL_CMP_PKIHEADER *hdr, const ASN1_OCTET_STRING *senderKID) { if (!ossl_assert(hdr != NULL)) return 0; return ossl_cmp_asn1_octet_string_set1(&hdr->senderKID, senderKID); } /* push the given text string to the given PKIFREETEXT ft */ int ossl_cmp_hdr_push0_freeText(OSSL_CMP_PKIHEADER *hdr, ASN1_UTF8STRING *text) { if (!ossl_assert(hdr != NULL && text != NULL)) return 0; if (hdr->freeText == NULL && (hdr->freeText = sk_ASN1_UTF8STRING_new_null()) == NULL) return 0; return sk_ASN1_UTF8STRING_push(hdr->freeText, text); } int ossl_cmp_hdr_push1_freeText(OSSL_CMP_PKIHEADER *hdr, ASN1_UTF8STRING *text) { if (!ossl_assert(hdr != NULL && text != NULL)) return 0; if (hdr->freeText == NULL && (hdr->freeText = sk_ASN1_UTF8STRING_new_null()) == NULL) return 0; return ossl_cmp_sk_ASN1_UTF8STRING_push_str(hdr->freeText, (char *)text->data, text->length); } int ossl_cmp_hdr_generalInfo_push0_item(OSSL_CMP_PKIHEADER *hdr, OSSL_CMP_ITAV *itav) { if (!ossl_assert(hdr != NULL && itav != NULL)) return 0; return OSSL_CMP_ITAV_push0_stack_item(&hdr->generalInfo, itav); } int ossl_cmp_hdr_generalInfo_push1_items(OSSL_CMP_PKIHEADER *hdr, const STACK_OF(OSSL_CMP_ITAV) *itavs) { int i; OSSL_CMP_ITAV *itav; if (!ossl_assert(hdr != NULL)) return 0; for (i = 0; i < sk_OSSL_CMP_ITAV_num(itavs); i++) { itav = OSSL_CMP_ITAV_dup(sk_OSSL_CMP_ITAV_value(itavs, i)); if (itav == NULL) return 0; if (!ossl_cmp_hdr_generalInfo_push0_item(hdr, itav)) { OSSL_CMP_ITAV_free(itav); return 0; } } return 1; } int ossl_cmp_hdr_set_implicitConfirm(OSSL_CMP_PKIHEADER *hdr) { OSSL_CMP_ITAV *itav; ASN1_TYPE *asn1null; if (!ossl_assert(hdr != NULL)) return 0; asn1null = (ASN1_TYPE *)ASN1_NULL_new(); if (asn1null == NULL) return 0; if ((itav = OSSL_CMP_ITAV_create(OBJ_nid2obj(NID_id_it_implicitConfirm), asn1null)) == NULL) goto err; if (!ossl_cmp_hdr_generalInfo_push0_item(hdr, itav)) goto err; return 1; err: ASN1_TYPE_free(asn1null); OSSL_CMP_ITAV_free(itav); return 0; } /* return 1 if implicitConfirm in the generalInfo field of the header is set */ int ossl_cmp_hdr_has_implicitConfirm(const OSSL_CMP_PKIHEADER *hdr) { int itavCount; int i; OSSL_CMP_ITAV *itav; if (!ossl_assert(hdr != NULL)) return 0; itavCount = sk_OSSL_CMP_ITAV_num(hdr->generalInfo); for (i = 0; i < itavCount; i++) { itav = sk_OSSL_CMP_ITAV_value(hdr->generalInfo, i); if (itav != NULL && OBJ_obj2nid(itav->infoType) == NID_id_it_implicitConfirm) return 1; } return 0; } /* * set ctx->transactionID in CMP header * if ctx->transactionID is NULL, a random one is created with 128 bit * according to section 5.1.1: * * It is RECOMMENDED that the clients fill the transactionID field with * 128 bits of (pseudo-) random data for the start of a transaction to * reduce the probability of having the transactionID in use at the server. */ int ossl_cmp_hdr_set_transactionID(OSSL_CMP_CTX *ctx, OSSL_CMP_PKIHEADER *hdr) { if (ctx->transactionID == NULL) { char *tid; if (!set_random(&ctx->transactionID, ctx, OSSL_CMP_TRANSACTIONID_LENGTH)) return 0; tid = i2s_ASN1_OCTET_STRING(NULL, ctx->transactionID); if (tid != NULL) ossl_cmp_log1(DEBUG, ctx, "Starting new transaction with ID=%s", tid); OPENSSL_free(tid); } return ossl_cmp_asn1_octet_string_set1(&hdr->transactionID, ctx->transactionID); } /* fill in all fields of the hdr according to the info given in ctx */ int ossl_cmp_hdr_init(OSSL_CMP_CTX *ctx, OSSL_CMP_PKIHEADER *hdr) { const X509_NAME *sender; const X509_NAME *rcp = NULL; if (!ossl_assert(ctx != NULL && hdr != NULL)) return 0; /* set the CMP version */ if (!ossl_cmp_hdr_set_pvno(hdr, OSSL_CMP_PVNO)) return 0; /* * If no protection cert nor oldCert nor CSR nor subject is given, * sender name is not known to the client and thus set to NULL-DN */ sender = ctx->cert != NULL ? X509_get_subject_name(ctx->cert) : ctx->oldCert != NULL ? X509_get_subject_name(ctx->oldCert) : ctx->p10CSR != NULL ? X509_REQ_get_subject_name(ctx->p10CSR) : ctx->subjectName; if (!ossl_cmp_hdr_set1_sender(hdr, sender)) return 0; /* determine recipient entry in PKIHeader */ if (ctx->recipient != NULL) rcp = ctx->recipient; else if (ctx->srvCert != NULL) rcp = X509_get_subject_name(ctx->srvCert); else if (ctx->issuer != NULL) rcp = ctx->issuer; else if (ctx->oldCert != NULL) rcp = X509_get_issuer_name(ctx->oldCert); else if (ctx->cert != NULL) rcp = X509_get_issuer_name(ctx->cert); if (!ossl_cmp_hdr_set1_recipient(hdr, rcp)) return 0; /* set current time as message time */ if (!ossl_cmp_hdr_update_messageTime(hdr)) return 0; if (ctx->recipNonce != NULL && !ossl_cmp_asn1_octet_string_set1(&hdr->recipNonce, ctx->recipNonce)) return 0; if (!ossl_cmp_hdr_set_transactionID(ctx, hdr)) return 0; /*- * set random senderNonce * according to section 5.1.1: * * senderNonce present * -- 128 (pseudo-)random bits * The senderNonce and recipNonce fields protect the PKIMessage against * replay attacks. The senderNonce will typically be 128 bits of * (pseudo-) random data generated by the sender, whereas the recipNonce * is copied from the senderNonce of the previous message in the * transaction. */ if (!set_random(&hdr->senderNonce, ctx, OSSL_CMP_SENDERNONCE_LENGTH)) return 0; /* store senderNonce - for cmp with recipNonce in next outgoing msg */ if (!OSSL_CMP_CTX_set1_senderNonce(ctx, hdr->senderNonce)) return 0; /*- * freeText [7] PKIFreeText OPTIONAL, * -- this may be used to indicate context-specific instructions * -- (this field is intended for human consumption) */ if (ctx->freeText != NULL && !ossl_cmp_hdr_push1_freeText(hdr, ctx->freeText)) return 0; return 1; }