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