1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345
|
/*
* Copyright 2007-2025 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 <openssl/rand.h> /* for RAND_bytes_ex() */
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;
}
STACK_OF(OSSL_CMP_ITAV)
*OSSL_CMP_HDR_get0_geninfo_ITAVs(const OSSL_CMP_PKIHEADER *hdr)
{
if (hdr == NULL) {
ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT);
return NULL;
}
return hdr->generalInfo;
}
/* 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));
}
/*
* 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 GENERAL_NAME_set1_X509_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 GENERAL_NAME_set1_X509_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, int 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;
}
|