1 /* $OpenBSD: cms_pwri.c,v 1.31 2024/01/14 18:40:24 tb Exp $ */ 2 /* 3 * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL 4 * project. 5 */ 6 /* ==================================================================== 7 * Copyright (c) 2009 The OpenSSL Project. All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in 18 * the documentation and/or other materials provided with the 19 * distribution. 20 * 21 * 3. All advertising materials mentioning features or use of this 22 * software must display the following acknowledgment: 23 * "This product includes software developed by the OpenSSL Project 24 * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 25 * 26 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 27 * endorse or promote products derived from this software without 28 * prior written permission. For written permission, please contact 29 * licensing@OpenSSL.org. 30 * 31 * 5. Products derived from this software may not be called "OpenSSL" 32 * nor may "OpenSSL" appear in their names without prior written 33 * permission of the OpenSSL Project. 34 * 35 * 6. Redistributions of any form whatsoever must retain the following 36 * acknowledgment: 37 * "This product includes software developed by the OpenSSL Project 38 * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 39 * 40 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 41 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 42 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 43 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 44 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 45 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 46 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 47 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 49 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 50 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 51 * OF THE POSSIBILITY OF SUCH DAMAGE. 52 * ==================================================================== 53 */ 54 55 #include <sys/types.h> 56 57 #include <stdlib.h> 58 #include <string.h> 59 60 #include <openssl/asn1.h> 61 #include <openssl/err.h> 62 #include <openssl/evp.h> 63 #include <openssl/cms.h> 64 #include <openssl/objects.h> 65 #include <openssl/x509.h> 66 67 #include "cms_local.h" 68 #include "evp_local.h" 69 #include "x509_local.h" 70 71 int 72 CMS_RecipientInfo_set0_password(CMS_RecipientInfo *ri, unsigned char *pass, 73 ssize_t passlen) 74 { 75 CMS_PasswordRecipientInfo *pwri; 76 77 if (ri->type != CMS_RECIPINFO_PASS) { 78 CMSerror(CMS_R_NOT_PWRI); 79 return 0; 80 } 81 82 pwri = ri->d.pwri; 83 pwri->pass = pass; 84 if (pass && passlen < 0) 85 passlen = strlen((char *)pass); 86 pwri->passlen = passlen; 87 88 return 1; 89 } 90 LCRYPTO_ALIAS(CMS_RecipientInfo_set0_password); 91 92 CMS_RecipientInfo * 93 CMS_add0_recipient_password(CMS_ContentInfo *cms, int iter, int wrap_nid, 94 int pbe_nid, unsigned char *pass, ssize_t passlen, 95 const EVP_CIPHER *kekciph) 96 { 97 CMS_RecipientInfo *ri = NULL; 98 CMS_EnvelopedData *env; 99 CMS_PasswordRecipientInfo *pwri; 100 EVP_CIPHER_CTX *ctx = NULL; 101 X509_ALGOR *encalg = NULL; 102 unsigned char iv[EVP_MAX_IV_LENGTH]; 103 int ivlen; 104 105 env = cms_get0_enveloped(cms); 106 if (!env) 107 return NULL; 108 109 if (wrap_nid <= 0) 110 wrap_nid = NID_id_alg_PWRI_KEK; 111 112 if (pbe_nid <= 0) 113 pbe_nid = NID_id_pbkdf2; 114 115 /* Get from enveloped data */ 116 if (kekciph == NULL) 117 kekciph = env->encryptedContentInfo->cipher; 118 119 if (kekciph == NULL) { 120 CMSerror(CMS_R_NO_CIPHER); 121 return NULL; 122 } 123 if (wrap_nid != NID_id_alg_PWRI_KEK) { 124 CMSerror(CMS_R_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM); 125 return NULL; 126 } 127 128 /* Setup algorithm identifier for cipher */ 129 encalg = X509_ALGOR_new(); 130 if (encalg == NULL) { 131 goto merr; 132 } 133 134 if ((ctx = EVP_CIPHER_CTX_new()) == NULL) 135 goto merr; 136 137 if (EVP_EncryptInit_ex(ctx, kekciph, NULL, NULL, NULL) <= 0) { 138 CMSerror(ERR_R_EVP_LIB); 139 goto err; 140 } 141 142 ivlen = EVP_CIPHER_CTX_iv_length(ctx); 143 144 if (ivlen > 0) { 145 arc4random_buf(iv, ivlen); 146 if (EVP_EncryptInit_ex(ctx, NULL, NULL, NULL, iv) <= 0) { 147 CMSerror(ERR_R_EVP_LIB); 148 goto err; 149 } 150 encalg->parameter = ASN1_TYPE_new(); 151 if (!encalg->parameter) { 152 CMSerror(ERR_R_MALLOC_FAILURE); 153 goto err; 154 } 155 if (EVP_CIPHER_param_to_asn1(ctx, encalg->parameter) <= 0) { 156 CMSerror(CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR); 157 goto err; 158 } 159 } 160 161 encalg->algorithm = OBJ_nid2obj(EVP_CIPHER_CTX_type(ctx)); 162 163 EVP_CIPHER_CTX_free(ctx); 164 ctx = NULL; 165 166 /* Initialize recipient info */ 167 ri = (CMS_RecipientInfo *)ASN1_item_new(&CMS_RecipientInfo_it); 168 if (ri == NULL) 169 goto merr; 170 171 ri->d.pwri = (CMS_PasswordRecipientInfo *)ASN1_item_new(&CMS_PasswordRecipientInfo_it); 172 if (ri->d.pwri == NULL) 173 goto merr; 174 ri->type = CMS_RECIPINFO_PASS; 175 176 pwri = ri->d.pwri; 177 /* Since this is overwritten, free up empty structure already there */ 178 X509_ALGOR_free(pwri->keyEncryptionAlgorithm); 179 pwri->keyEncryptionAlgorithm = X509_ALGOR_new(); 180 if (pwri->keyEncryptionAlgorithm == NULL) 181 goto merr; 182 pwri->keyEncryptionAlgorithm->algorithm = OBJ_nid2obj(wrap_nid); 183 pwri->keyEncryptionAlgorithm->parameter = ASN1_TYPE_new(); 184 if (pwri->keyEncryptionAlgorithm->parameter == NULL) 185 goto merr; 186 187 if (!ASN1_item_pack(encalg, &X509_ALGOR_it, 188 &pwri->keyEncryptionAlgorithm->parameter->value.sequence)) 189 goto merr; 190 pwri->keyEncryptionAlgorithm->parameter->type = V_ASN1_SEQUENCE; 191 192 X509_ALGOR_free(encalg); 193 encalg = NULL; 194 195 /* Setup PBE algorithm */ 196 197 pwri->keyDerivationAlgorithm = PKCS5_pbkdf2_set(iter, NULL, 0, -1, -1); 198 199 if (!pwri->keyDerivationAlgorithm) 200 goto err; 201 202 CMS_RecipientInfo_set0_password(ri, pass, passlen); 203 pwri->version = 0; 204 205 if (!sk_CMS_RecipientInfo_push(env->recipientInfos, ri)) 206 goto merr; 207 208 return ri; 209 210 merr: 211 CMSerror(ERR_R_MALLOC_FAILURE); 212 err: 213 EVP_CIPHER_CTX_free(ctx); 214 if (ri) 215 ASN1_item_free((ASN1_VALUE *)ri, &CMS_RecipientInfo_it); 216 X509_ALGOR_free(encalg); 217 218 return NULL; 219 } 220 LCRYPTO_ALIAS(CMS_add0_recipient_password); 221 222 /* 223 * This is an implementation of the key wrapping mechanism in RFC3211, at 224 * some point this should go into EVP. 225 */ 226 227 static int 228 kek_unwrap_key(unsigned char *out, size_t *outlen, const unsigned char *in, 229 size_t inlen, EVP_CIPHER_CTX *ctx) 230 { 231 size_t blocklen = EVP_CIPHER_CTX_block_size(ctx); 232 unsigned char *tmp; 233 int outl, rv = 0; 234 235 if (inlen < 2 * blocklen) { 236 /* too small */ 237 return 0; 238 } 239 if (inlen % blocklen) { 240 /* Invalid size */ 241 return 0; 242 } 243 if ((tmp = malloc(inlen)) == NULL) { 244 CMSerror(ERR_R_MALLOC_FAILURE); 245 return 0; 246 } 247 248 /* setup IV by decrypting last two blocks */ 249 if (!EVP_DecryptUpdate(ctx, tmp + inlen - 2 * blocklen, &outl, 250 in + inlen - 2 * blocklen, blocklen * 2) 251 /* 252 * Do a decrypt of last decrypted block to set IV to correct value 253 * output it to start of buffer so we don't corrupt decrypted block 254 * this works because buffer is at least two block lengths long. 255 */ 256 || !EVP_DecryptUpdate(ctx, tmp, &outl, tmp + inlen - blocklen, blocklen) 257 /* Can now decrypt first n - 1 blocks */ 258 || !EVP_DecryptUpdate(ctx, tmp, &outl, in, inlen - blocklen) 259 260 /* Reset IV to original value */ 261 || !EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, NULL) 262 /* Decrypt again */ 263 || !EVP_DecryptUpdate(ctx, tmp, &outl, tmp, inlen)) 264 goto err; 265 /* Check check bytes */ 266 if (((tmp[1] ^ tmp[4]) & (tmp[2] ^ tmp[5]) & (tmp[3] ^ tmp[6])) != 0xff) { 267 /* Check byte failure */ 268 goto err; 269 } 270 if (inlen < (size_t)(tmp[0] - 4)) { 271 /* Invalid length value */ 272 goto err; 273 } 274 *outlen = (size_t)tmp[0]; 275 memcpy(out, tmp + 4, *outlen); 276 rv = 1; 277 278 err: 279 freezero(tmp, inlen); 280 281 return rv; 282 } 283 284 static int 285 kek_wrap_key(unsigned char *out, size_t *outlen, const unsigned char *in, 286 size_t inlen, EVP_CIPHER_CTX *ctx) 287 { 288 size_t blocklen = EVP_CIPHER_CTX_block_size(ctx); 289 size_t olen; 290 int dummy; 291 292 /* 293 * First decide length of output buffer: need header and round up to 294 * multiple of block length. 295 */ 296 olen = (inlen + 4 + blocklen - 1) / blocklen; 297 olen *= blocklen; 298 if (olen < 2 * blocklen) { 299 /* Key too small */ 300 return 0; 301 } 302 if (inlen > 0xFF) { 303 /* Key too large */ 304 return 0; 305 } 306 if (out) { 307 /* Set header */ 308 out[0] = (unsigned char)inlen; 309 out[1] = in[0] ^ 0xFF; 310 out[2] = in[1] ^ 0xFF; 311 out[3] = in[2] ^ 0xFF; 312 memcpy(out + 4, in, inlen); 313 /* Add random padding to end */ 314 if (olen > inlen + 4) 315 arc4random_buf(out + 4 + inlen, olen - 4 - inlen); 316 /* Encrypt twice */ 317 if (!EVP_EncryptUpdate(ctx, out, &dummy, out, olen) || 318 !EVP_EncryptUpdate(ctx, out, &dummy, out, olen)) 319 return 0; 320 } 321 322 *outlen = olen; 323 324 return 1; 325 } 326 327 /* Encrypt/Decrypt content key in PWRI recipient info */ 328 329 int 330 cms_RecipientInfo_pwri_crypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri, 331 int en_de) 332 { 333 CMS_EncryptedContentInfo *ec; 334 CMS_PasswordRecipientInfo *pwri; 335 int r = 0; 336 X509_ALGOR *algtmp, *kekalg = NULL; 337 EVP_CIPHER_CTX *kekctx = NULL; 338 const EVP_CIPHER *kekcipher; 339 unsigned char *key = NULL; 340 size_t keylen; 341 342 ec = cms->d.envelopedData->encryptedContentInfo; 343 344 pwri = ri->d.pwri; 345 346 if (!pwri->pass) { 347 CMSerror(CMS_R_NO_PASSWORD); 348 return 0; 349 } 350 algtmp = pwri->keyEncryptionAlgorithm; 351 352 if (!algtmp || OBJ_obj2nid(algtmp->algorithm) != NID_id_alg_PWRI_KEK) { 353 CMSerror(CMS_R_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM); 354 return 0; 355 } 356 357 if (algtmp->parameter != NULL && 358 algtmp->parameter->type == V_ASN1_SEQUENCE && 359 algtmp->parameter->value.sequence != NULL) 360 kekalg = ASN1_item_unpack(algtmp->parameter->value.sequence, 361 &X509_ALGOR_it); 362 363 if (kekalg == NULL) { 364 CMSerror(CMS_R_INVALID_KEY_ENCRYPTION_PARAMETER); 365 return 0; 366 } 367 368 kekcipher = EVP_get_cipherbyobj(kekalg->algorithm); 369 if (!kekcipher) { 370 CMSerror(CMS_R_UNKNOWN_CIPHER); 371 return 0; 372 } 373 374 kekctx = EVP_CIPHER_CTX_new(); 375 if (kekctx == NULL) { 376 CMSerror(ERR_R_MALLOC_FAILURE); 377 return 0; 378 } 379 /* Fixup cipher based on AlgorithmIdentifier to set IV etc */ 380 if (!EVP_CipherInit_ex(kekctx, kekcipher, NULL, NULL, NULL, en_de)) 381 goto err; 382 EVP_CIPHER_CTX_set_padding(kekctx, 0); 383 if (EVP_CIPHER_asn1_to_param(kekctx, kekalg->parameter) <= 0) { 384 CMSerror(CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR); 385 goto err; 386 } 387 388 algtmp = pwri->keyDerivationAlgorithm; 389 390 /* Finish password based key derivation to setup key in "ctx" */ 391 392 if (EVP_PBE_CipherInit(algtmp->algorithm, (char *)pwri->pass, 393 pwri->passlen, algtmp->parameter, kekctx, en_de) < 0) { 394 CMSerror(ERR_R_EVP_LIB); 395 goto err; 396 } 397 398 /* Finally wrap/unwrap the key */ 399 400 if (en_de) { 401 if (!kek_wrap_key(NULL, &keylen, ec->key, ec->keylen, kekctx)) 402 goto err; 403 404 key = malloc(keylen); 405 if (key == NULL) 406 goto err; 407 408 if (!kek_wrap_key(key, &keylen, ec->key, ec->keylen, kekctx)) 409 goto err; 410 pwri->encryptedKey->data = key; 411 pwri->encryptedKey->length = keylen; 412 } else { 413 key = malloc(pwri->encryptedKey->length); 414 if (key == NULL) { 415 CMSerror(ERR_R_MALLOC_FAILURE); 416 goto err; 417 } 418 if (!kek_unwrap_key(key, &keylen, pwri->encryptedKey->data, 419 pwri->encryptedKey->length, kekctx)) { 420 CMSerror(CMS_R_UNWRAP_FAILURE); 421 goto err; 422 } 423 424 freezero(ec->key, ec->keylen); 425 ec->key = key; 426 ec->keylen = keylen; 427 } 428 429 r = 1; 430 431 err: 432 EVP_CIPHER_CTX_free(kekctx); 433 if (!r) 434 free(key); 435 X509_ALGOR_free(kekalg); 436 437 return r; 438 } 439