X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=crypto%2Fcms%2Fcms_smime.c;h=12fc844d934e7657a29c9c2ef5f884917a05098d;hp=dcc0e6ba10c3c73b996669f42efa5ffdcab94d66;hb=54571ba004e9392b93bc1f452cdf62431f2cde5a;hpb=6e3bc4f0730a3cb7d2d263153cb234da51637b38 diff --git a/crypto/cms/cms_smime.c b/crypto/cms/cms_smime.c index dcc0e6ba10..12fc844d93 100644 --- a/crypto/cms/cms_smime.c +++ b/crypto/cms/cms_smime.c @@ -65,18 +65,22 @@ static int cms_copy_content(BIO *out, BIO *in, unsigned int flags) int r = 0, i; BIO *tmpout = NULL; - if(flags & CMS_TEXT) + if (out == NULL) + tmpout = BIO_new(BIO_s_null()); + else if (flags & CMS_TEXT) { tmpout = BIO_new(BIO_s_mem()); - if(!tmpout) - { - CMSerr(CMS_F_CMS_COPY_CONTENT,ERR_R_MALLOC_FAILURE); - goto err; - } + BIO_set_mem_eof_return(tmpout, 0); } else tmpout = out; + if(!tmpout) + { + CMSerr(CMS_F_CMS_COPY_CONTENT,ERR_R_MALLOC_FAILURE); + goto err; + } + /* Read all content through chain to process digest, decrypt etc */ for (;;) { @@ -88,11 +92,13 @@ static int cms_copy_content(BIO *out, BIO *in, unsigned int flags) if (!BIO_get_cipher_status(in)) goto err; } + if (i < 0) + goto err; break; } - if (tmpout) - BIO_write(tmpout, buf, i); + if (tmpout && (BIO_write(tmpout, buf, i) != i)) + goto err; } if(flags & CMS_TEXT) @@ -124,6 +130,23 @@ static int check_content(CMS_ContentInfo *cms) return 1; } +static void do_free_upto(BIO *f, BIO *upto) + { + if (upto) + { + BIO *tbio; + do + { + tbio = BIO_pop(f); + BIO_free(f); + f = tbio; + } + while (f != upto); + } + else + BIO_free_all(f); + } + int CMS_data(CMS_ContentInfo *cms, BIO *out, unsigned int flags) { BIO *cont; @@ -148,7 +171,7 @@ CMS_ContentInfo *CMS_data_create(BIO *in, unsigned int flags) if (!cms) return NULL; - if ((flags & CMS_STREAM) || CMS_final(cms, in, flags)) + if ((flags & CMS_STREAM) || CMS_final(cms, in, NULL, flags)) return cms; CMS_ContentInfo_free(cms); @@ -176,7 +199,7 @@ int CMS_digest_verify(CMS_ContentInfo *cms, BIO *dcont, BIO *out, r = cms_copy_content(out, cont, flags); if (r) r = cms_DigestedData_do_final(cms, cont, 1); - BIO_free_all(cont); + do_free_upto(cont, dcont); return r; } @@ -193,7 +216,7 @@ CMS_ContentInfo *CMS_digest_create(BIO *in, const EVP_MD *md, if(!(flags & CMS_DETACHED)) CMS_set_detached(cms, 0); - if ((flags & CMS_STREAM) || CMS_final(cms, in, flags)) + if ((flags & CMS_STREAM) || CMS_final(cms, in, NULL, flags)) return cms; CMS_ContentInfo_free(cms); @@ -222,7 +245,7 @@ int CMS_EncryptedData_decrypt(CMS_ContentInfo *cms, if (!cont) return 0; r = cms_copy_content(out, cont, flags); - BIO_free_all(cont); + do_free_upto(cont, dcont); return r; } @@ -245,7 +268,8 @@ CMS_ContentInfo *CMS_EncryptedData_encrypt(BIO *in, const EVP_CIPHER *cipher, if(!(flags & CMS_DETACHED)) CMS_set_detached(cms, 0); - if ((flags & (CMS_STREAM|CMS_PARTIAL)) || CMS_final(cms, in, flags)) + if ((flags & (CMS_STREAM|CMS_PARTIAL)) + || CMS_final(cms, in, NULL, flags)) return cms; CMS_ContentInfo_free(cms); @@ -268,7 +292,7 @@ static int cms_signerinfo_verify_cert(CMS_SignerInfo *si, CMS_R_STORE_INIT_ERROR); goto err; } - X509_STORE_CTX_set_purpose(&ctx, X509_PURPOSE_SMIME_SIGN); + X509_STORE_CTX_set_default(&ctx, "smime_sign"); if (crls) X509_STORE_CTX_set0_crls(&ctx, crls); @@ -335,7 +359,8 @@ int CMS_verify(CMS_ContentInfo *cms, STACK_OF(X509) *certs, if (!(flags & CMS_NO_SIGNER_CERT_VERIFY)) { cms_certs = CMS_get1_certs(cms); - crls = CMS_get1_crls(cms); + if (!(flags & CMS_NOCRL)) + crls = CMS_get1_crls(cms); for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) { si = sk_CMS_SignerInfo_value(sinfos, i); @@ -408,8 +433,9 @@ int CMS_verify(CMS_ContentInfo *cms, STACK_OF(X509) *certs, err: if (dcont && (tmpin == dcont)) - BIO_pop(cmsbio); - BIO_free_all(cmsbio); + do_free_upto(cmsbio, dcont); + else + BIO_free_all(cmsbio); if (cms_certs) sk_X509_pop_free(cms_certs, X509_free); @@ -419,36 +445,49 @@ int CMS_verify(CMS_ContentInfo *cms, STACK_OF(X509) *certs, return ret; } +int CMS_verify_receipt(CMS_ContentInfo *rcms, CMS_ContentInfo *ocms, + STACK_OF(X509) *certs, + X509_STORE *store, unsigned int flags) + { + int r; + flags &= ~(CMS_DETACHED|CMS_TEXT); + r = CMS_verify(rcms, certs, store, NULL, NULL, flags); + if (r <= 0) + return r; + return cms_Receipt_verify(rcms, ocms); + } + CMS_ContentInfo *CMS_sign(X509 *signcert, EVP_PKEY *pkey, STACK_OF(X509) *certs, BIO *data, unsigned int flags) { CMS_ContentInfo *cms; int i; + cms = CMS_ContentInfo_new(); - if (!cms) + if (!cms || !CMS_SignedData_init(cms)) goto merr; + if (pkey && !CMS_add1_signer(cms, signcert, pkey, NULL, flags)) { CMSerr(CMS_F_CMS_SIGN, CMS_R_ADD_SIGNER_ERROR); goto err; } + for (i = 0; i < sk_X509_num(certs); i++) { X509 *x = sk_X509_value(certs, i); if (!CMS_add1_cert(cms, x)) goto merr; } - /* If no signer or certs initialize signedData */ - if (!pkey && !i && !CMS_SignedData_init(cms)) - goto merr; if(!(flags & CMS_DETACHED)) CMS_set_detached(cms, 0); - if ((flags & (CMS_STREAM|CMS_PARTIAL)) || CMS_final(cms, data, flags)) + if ((flags & (CMS_STREAM|CMS_PARTIAL)) + || CMS_final(cms, data, NULL, flags)) return cms; - - return cms; + else + goto err; merr: CMSerr(CMS_F_CMS_SIGN, ERR_R_MALLOC_FAILURE); @@ -459,6 +498,78 @@ CMS_ContentInfo *CMS_sign(X509 *signcert, EVP_PKEY *pkey, STACK_OF(X509) *certs, return NULL; } +CMS_ContentInfo *CMS_sign_receipt(CMS_SignerInfo *si, + X509 *signcert, EVP_PKEY *pkey, + STACK_OF(X509) *certs, + unsigned int flags) + { + CMS_SignerInfo *rct_si; + CMS_ContentInfo *cms = NULL; + ASN1_OCTET_STRING **pos, *os; + BIO *rct_cont = NULL; + int r = 0; + + flags &= ~(CMS_STREAM|CMS_TEXT); + /* Not really detached but avoids content being allocated */ + flags |= CMS_PARTIAL|CMS_BINARY|CMS_DETACHED; + if (!pkey || !signcert) + { + CMSerr(CMS_F_CMS_SIGN_RECEIPT, CMS_R_NO_KEY_OR_CERT); + return NULL; + } + + /* Initialize signed data */ + + cms = CMS_sign(NULL, NULL, certs, NULL, flags); + if (!cms) + goto err; + + /* Set inner content type to signed receipt */ + if (!CMS_set1_eContentType(cms, OBJ_nid2obj(NID_id_smime_ct_receipt))) + goto err; + + rct_si = CMS_add1_signer(cms, signcert, pkey, NULL, flags); + if (!rct_si) + { + CMSerr(CMS_F_CMS_SIGN_RECEIPT, CMS_R_ADD_SIGNER_ERROR); + goto err; + } + + os = cms_encode_Receipt(si); + + if (!os) + goto err; + + /* Set content to digest */ + rct_cont = BIO_new_mem_buf(os->data, os->length); + if (!rct_cont) + goto err; + + /* Add msgSigDigest attribute */ + + if (!cms_msgSigDigest_add1(rct_si, si)) + goto err; + + /* Finalize structure */ + if (!CMS_final(cms, rct_cont, NULL, flags)) + goto err; + + /* Set embedded content */ + pos = CMS_get0_content(cms); + *pos = os; + + r = 1; + + err: + if (rct_cont) + BIO_free(rct_cont); + if (r) + return cms; + CMS_ContentInfo_free(cms); + return NULL; + + } + CMS_ContentInfo *CMS_encrypt(STACK_OF(X509) *certs, BIO *data, const EVP_CIPHER *cipher, unsigned int flags) { @@ -481,10 +592,11 @@ CMS_ContentInfo *CMS_encrypt(STACK_OF(X509) *certs, BIO *data, if(!(flags & CMS_DETACHED)) CMS_set_detached(cms, 0); - if ((flags & (CMS_STREAM|CMS_PARTIAL)) || CMS_final(cms, data, flags)) + if ((flags & (CMS_STREAM|CMS_PARTIAL)) + || CMS_final(cms, data, NULL, flags)) return cms; - - return cms; + else + goto err; merr: CMSerr(CMS_F_CMS_ENCRYPT, ERR_R_MALLOC_FAILURE); @@ -493,12 +605,87 @@ CMS_ContentInfo *CMS_encrypt(STACK_OF(X509) *certs, BIO *data, CMS_ContentInfo_free(cms); return NULL; } + +int CMS_decrypt_set1_pkey(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert) + { + STACK_OF(CMS_RecipientInfo) *ris; + CMS_RecipientInfo *ri; + int i, r; + ris = CMS_get0_RecipientInfos(cms); + for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++) + { + ri = sk_CMS_RecipientInfo_value(ris, i); + if (CMS_RecipientInfo_type(ri) != CMS_RECIPINFO_TRANS) + continue; + /* If we have a cert try matching RecipientInfo + * otherwise try them all. + */ + if (!cert || (CMS_RecipientInfo_ktri_cert_cmp(ri, cert) == 0)) + { + CMS_RecipientInfo_set0_pkey(ri, pk); + r = CMS_RecipientInfo_decrypt(cms, ri); + CMS_RecipientInfo_set0_pkey(ri, NULL); + if (r > 0) + return 1; + if (cert) + { + CMSerr(CMS_F_CMS_DECRYPT_SET1_PKEY, + CMS_R_DECRYPT_ERROR); + return 0; + } + ERR_clear_error(); + } + } + + CMSerr(CMS_F_CMS_DECRYPT_SET1_PKEY, CMS_R_NO_MATCHING_RECIPIENT); + return 0; + + } + +int CMS_decrypt_set1_key(CMS_ContentInfo *cms, + unsigned char *key, size_t keylen, + unsigned char *id, size_t idlen) + { + STACK_OF(CMS_RecipientInfo) *ris; + CMS_RecipientInfo *ri; + int i, r; + ris = CMS_get0_RecipientInfos(cms); + for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++) + { + ri = sk_CMS_RecipientInfo_value(ris, i); + if (CMS_RecipientInfo_type(ri) != CMS_RECIPINFO_KEK) + continue; + + /* If we have an id try matching RecipientInfo + * otherwise try them all. + */ + if (!id || (CMS_RecipientInfo_kekri_id_cmp(ri, id, idlen) == 0)) + { + CMS_RecipientInfo_set0_key(ri, key, keylen); + r = CMS_RecipientInfo_decrypt(cms, ri); + CMS_RecipientInfo_set0_key(ri, NULL, 0); + if (r > 0) + return 1; + if (id) + { + CMSerr(CMS_F_CMS_DECRYPT_SET1_KEY, + CMS_R_DECRYPT_ERROR); + return 0; + } + ERR_clear_error(); + } + } + + CMSerr(CMS_F_CMS_DECRYPT_SET1_KEY, CMS_R_NO_MATCHING_RECIPIENT); + return 0; + + } int CMS_decrypt(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert, BIO *dcont, BIO *out, unsigned int flags) { - int i, r; + int r; BIO *cont; if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_enveloped) { @@ -507,51 +694,22 @@ int CMS_decrypt(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert, } if (!dcont && !check_content(cms)) return 0; - if (pk) - { - STACK_OF(CMS_RecipientInfo) *ris; - CMS_RecipientInfo *ri; - ris = CMS_get0_RecipientInfos(cms); - for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++) - { - ri = sk_CMS_RecipientInfo_value(ris, i); - if (CMS_RecipientInfo_type(ri) != CMS_RECIPINFO_TRANS) - continue; - /* If we have a cert try matching RecipientInfo - * otherwise try them all. - */ - if (!cert || - (CMS_RecipientInfo_ktri_cert_cmp(ri, cert) == 0)) - { - CMS_RecipientInfo_set0_pkey(ri, pk); - r = CMS_RecipientInfo_decrypt(cms, ri); - CMS_RecipientInfo_set0_pkey(ri, NULL); - if (r > 0) - break; - if (cert) - return 0; - } - } + if (pk && !CMS_decrypt_set1_pkey(cms, pk, cert)) + return 0; - if (i == sk_CMS_RecipientInfo_num(ris)) - { - CMSerr(CMS_F_CMS_DECRYPT, CMS_R_NO_MATCHING_RECIPIENT); - return 0; - } - } cont = CMS_dataInit(cms, dcont); if (!cont) return 0; r = cms_copy_content(out, cont, flags); - BIO_free_all(cont); + do_free_upto(cont, dcont); return r; } -int CMS_final(CMS_ContentInfo *cms, BIO *data, int flags) +int CMS_final(CMS_ContentInfo *cms, BIO *data, BIO *dcont, unsigned int flags) { BIO *cmsbio; int ret = 0; - if (!(cmsbio = CMS_dataInit(cms, NULL))) + if (!(cmsbio = CMS_dataInit(cms, dcont))) { CMSerr(CMS_F_CMS_FINAL,ERR_R_MALLOC_FAILURE); return 0; @@ -571,7 +729,7 @@ int CMS_final(CMS_ContentInfo *cms, BIO *data, int flags) ret = 1; err: - BIO_free_all(cmsbio); + do_free_upto(cmsbio, dcont); return ret; @@ -598,7 +756,7 @@ int CMS_uncompress(CMS_ContentInfo *cms, BIO *dcont, BIO *out, if (!cont) return 0; r = cms_copy_content(out, cont, flags); - BIO_free_all(cont); + do_free_upto(cont, dcont); return r; } @@ -614,7 +772,7 @@ CMS_ContentInfo *CMS_compress(BIO *in, int comp_nid, unsigned int flags) if(!(flags & CMS_DETACHED)) CMS_set_detached(cms, 0); - if ((flags & CMS_STREAM) || CMS_final(cms, in, flags)) + if ((flags & CMS_STREAM) || CMS_final(cms, in, NULL, flags)) return cms; CMS_ContentInfo_free(cms);