From b820455c6e0aa38e7bdf121ec971f72e0eb097d0 Mon Sep 17 00:00:00 2001 From: "Dr. Stephen Henson" Date: Fri, 14 Mar 2008 13:21:48 +0000 Subject: [PATCH] Encrypted Data type processing. Add options to cms utility and run section 7 tests in RFC4134. --- apps/cms.c | 27 +++++++++++++++++++++++++++ crypto/cms/cms.h | 10 ++++++++++ crypto/cms/cms_enc.c | 23 ++++++++++++----------- crypto/cms/cms_err.c | 3 +++ crypto/cms/cms_lcl.h | 6 ++++++ crypto/cms/cms_lib.c | 6 +++++- crypto/cms/cms_smime.c | 34 ++++++++++++++++++++++++++++++++++ test/runex.pl | 36 ++++++++++++++++++++++++++++++++++-- 8 files changed, 131 insertions(+), 14 deletions(-) diff --git a/apps/cms.c b/apps/cms.c index 9fd0aa0a86..908e05acf0 100644 --- a/apps/cms.c +++ b/apps/cms.c @@ -86,6 +86,7 @@ static int smime_cb(int ok, X509_STORE_CTX *ctx); #define SMIME_DIGEST_CREATE (10 | SMIME_OP) #define SMIME_UNCOMPRESS (11 | SMIME_IP) #define SMIME_COMPRESS (12 | SMIME_OP) +#define SMIME_ENCRYPTED_DECRYPT (13 | SMIME_IP) int MAIN(int, char **); @@ -121,6 +122,8 @@ int MAIN(int argc, char **argv) #ifndef OPENSSL_NO_ENGINE char *engine=NULL; #endif + unsigned char *secret_key = NULL; + size_t secret_keylen; X509_VERIFY_PARAM *vpm = NULL; @@ -164,6 +167,8 @@ int MAIN(int argc, char **argv) operation = SMIME_COMPRESS; else if (!strcmp (*args, "-uncompress")) operation = SMIME_UNCOMPRESS; + else if (!strcmp (*args, "-EncrypedData_decrypt")) + operation = SMIME_ENCRYPTED_DECRYPT; #ifndef OPENSSL_NO_DES else if (!strcmp (*args, "-des3")) cipher = EVP_des_ede3_cbc(); @@ -233,6 +238,20 @@ int MAIN(int argc, char **argv) flags |= CMS_NOOLDMIMETYPE; else if (!strcmp (*args, "-crlfeol")) flags |= CMS_CRLFEOL; + else if (!strcmp(*args,"-secretkey")) + { + long ltmp; + if (!args[1]) + goto argerr; + args++; + secret_key = string_to_hex(*args, <mp); + if (!secret_key) + { + BIO_printf(bio_err, "Invalid key %s\n", *args); + goto argerr; + } + secret_keylen = (size_t)ltmp; + } else if (!strcmp(*args,"-rand")) { if (!args[1]) @@ -810,6 +829,12 @@ int MAIN(int argc, char **argv) goto end; } } + else if (operation == SMIME_ENCRYPTED_DECRYPT) + { + if (!CMS_EncryptedData_decrypt(cms, secret_key, secret_keylen, + indata, out, flags)) + goto end; + } else if (operation == SMIME_VERIFY) { if (CMS_verify(cms, other, store, indata, out, flags) > 0) @@ -878,6 +903,8 @@ end: sk_free(sksigners); if (skkeys) sk_free(skkeys); + if (secret_key) + OPENSSL_free(secret_key); X509_STORE_free(store); X509_free(cert); X509_free(recip); diff --git a/crypto/cms/cms.h b/crypto/cms/cms.h index 0df4b0f4cf..a95dda906e 100644 --- a/crypto/cms/cms.h +++ b/crypto/cms/cms.h @@ -138,6 +138,13 @@ int CMS_digest_verify(CMS_ContentInfo *cms, BIO *dcont, BIO *out, CMS_ContentInfo *CMS_digest_create(BIO *in, const EVP_MD *md, unsigned int flags); +int CMS_EncryptedData_decrypt(CMS_ContentInfo *cms, + const unsigned char *key, size_t keylen, + BIO *dcont, BIO *out, unsigned int flags); + +int CMS_EncryptedData_set1_key(BIO *b, CMS_ContentInfo *cms, + const unsigned char *key, size_t keylen); + int CMS_verify(CMS_ContentInfo *cms, STACK_OF(X509) *certs, X509_STORE *store, BIO *dcont, BIO *out, unsigned int flags); @@ -255,6 +262,8 @@ void ERR_load_CMS_strings(void); #define CMS_F_CMS_DIGESTEDDATA_DO_FINAL 112 #define CMS_F_CMS_DIGEST_VERIFY 113 #define CMS_F_CMS_ENCRYPTEDCONTENT_TO_BIO 138 +#define CMS_F_CMS_ENCRYPTEDDATA_DECRYPT 140 +#define CMS_F_CMS_ENCRYPTED_DATA_DECRYPT 139 #define CMS_F_CMS_ENVELOPED_DATA_INIT 114 #define CMS_F_CMS_FINAL 115 #define CMS_F_CMS_GET0_CERTIFICATE_CHOICES 116 @@ -315,6 +324,7 @@ void ERR_load_CMS_strings(void); #define CMS_R_TYPE_NOT_COMPRESSED_DATA 128 #define CMS_R_TYPE_NOT_DATA 129 #define CMS_R_TYPE_NOT_DIGESTED_DATA 130 +#define CMS_R_TYPE_NOT_ENCRYPTED_DATA 142 #define CMS_R_UNABLE_TO_FINALIZE_CONTEXT 131 #define CMS_R_UNKNOWN_CIPHER 141 #define CMS_R_UNKNOWN_DIGEST_ALGORIHM 132 diff --git a/crypto/cms/cms_enc.c b/crypto/cms/cms_enc.c index 084bc12466..b395bc499b 100644 --- a/crypto/cms/cms_enc.c +++ b/crypto/cms/cms_enc.c @@ -132,18 +132,11 @@ int cms_bio_to_EncryptedContent(CMS_EncryptedContentInfo *ec, /* Return BIO based on EncryptedContentInfo and key */ -BIO *cms_EncryptedContent_to_bio(CMS_EncryptedContentInfo *ec, +int cms_EncryptedContent_to_bio(BIO *b, CMS_EncryptedContentInfo *ec, const unsigned char *key, int keylen) { - BIO *b; EVP_CIPHER_CTX *ctx; const EVP_CIPHER *ciph; - b = BIO_new(BIO_f_cipher()); - if (!b) - { - CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_TO_BIO, ERR_R_MALLOC_FAILURE); - return NULL; - } BIO_get_cipher_ctx(b, &ctx); ciph = EVP_get_cipherbyobj(ec->contentEncryptionAlgorithm->algorithm); @@ -187,10 +180,18 @@ BIO *cms_EncryptedContent_to_bio(CMS_EncryptedContentInfo *ec, CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR); goto err; } - return b; + return 1; err: - BIO_free(b); - return NULL; + return 0; } +int CMS_EncryptedData_set1_key(BIO *b, CMS_ContentInfo *cms, + const unsigned char *key, size_t keylen) + { + CMS_EncryptedContentInfo *ec; + if (OBJ_obj2nid(cms->contentType) != NID_pkcs7_encrypted) + return 0; + ec = cms->d.encryptedData->encryptedContentInfo; + return cms_EncryptedContent_to_bio(b, ec, key, keylen); + } diff --git a/crypto/cms/cms_err.c b/crypto/cms/cms_err.c index 8a45c059a8..6fb6939b93 100644 --- a/crypto/cms/cms_err.c +++ b/crypto/cms/cms_err.c @@ -87,6 +87,8 @@ static ERR_STRING_DATA CMS_str_functs[]= {ERR_FUNC(CMS_F_CMS_DIGESTEDDATA_DO_FINAL), "CMS_DIGESTEDDATA_DO_FINAL"}, {ERR_FUNC(CMS_F_CMS_DIGEST_VERIFY), "CMS_digest_verify"}, {ERR_FUNC(CMS_F_CMS_ENCRYPTEDCONTENT_TO_BIO), "CMS_ENCRYPTEDCONTENT_TO_BIO"}, +{ERR_FUNC(CMS_F_CMS_ENCRYPTEDDATA_DECRYPT), "CMS_EncryptedData_decrypt"}, +{ERR_FUNC(CMS_F_CMS_ENCRYPTED_DATA_DECRYPT), "CMS_ENCRYPTED_DATA_DECRYPT"}, {ERR_FUNC(CMS_F_CMS_ENVELOPED_DATA_INIT), "CMS_ENVELOPED_DATA_INIT"}, {ERR_FUNC(CMS_F_CMS_FINAL), "CMS_final"}, {ERR_FUNC(CMS_F_CMS_GET0_CERTIFICATE_CHOICES), "CMS_GET0_CERTIFICATE_CHOICES"}, @@ -150,6 +152,7 @@ static ERR_STRING_DATA CMS_str_reasons[]= {ERR_REASON(CMS_R_TYPE_NOT_COMPRESSED_DATA),"type not compressed data"}, {ERR_REASON(CMS_R_TYPE_NOT_DATA) ,"type not data"}, {ERR_REASON(CMS_R_TYPE_NOT_DIGESTED_DATA),"type not digested data"}, +{ERR_REASON(CMS_R_TYPE_NOT_ENCRYPTED_DATA),"type not encrypted data"}, {ERR_REASON(CMS_R_UNABLE_TO_FINALIZE_CONTEXT),"unable to finalize context"}, {ERR_REASON(CMS_R_UNKNOWN_CIPHER) ,"unknown cipher"}, {ERR_REASON(CMS_R_UNKNOWN_DIGEST_ALGORIHM),"unknown digest algorihm"}, diff --git a/crypto/cms/cms_lcl.h b/crypto/cms/cms_lcl.h index e33c274a10..cc22e00d53 100644 --- a/crypto/cms/cms_lcl.h +++ b/crypto/cms/cms_lcl.h @@ -411,6 +411,12 @@ void cms_DigestAlgorithm_set(X509_ALGOR *alg, const EVP_MD *md); BIO *cms_DigestAlgorithm_init_bio(X509_ALGOR *digestAlgorithm); int cms_DigestAlgorithm_find_ctx(EVP_MD_CTX *mctx, BIO *chain, X509_ALGOR *mdalg); + +int cms_bio_to_EncryptedContent(CMS_EncryptedContentInfo *ec, + const unsigned char *key, int keylen, + BIO *b); +int cms_EncryptedContent_to_bio(BIO *b, CMS_EncryptedContentInfo *ec, + const unsigned char *key, int keylen); #ifdef __cplusplus } diff --git a/crypto/cms/cms_lib.c b/crypto/cms/cms_lib.c index 24ab0e7ba5..f2169e138b 100644 --- a/crypto/cms/cms_lib.c +++ b/crypto/cms/cms_lib.c @@ -139,6 +139,10 @@ BIO *CMS_dataInit(CMS_ContentInfo *cms, BIO *icont) break; #endif + case NID_pkcs7_encrypted: + cmsbio = BIO_new(BIO_f_cipher()); + break; + default: CMSerr(CMS_F_CMS_DATAINIT, CMS_R_UNSUPPORTED_TYPE); return NULL; @@ -152,7 +156,7 @@ BIO *CMS_dataInit(CMS_ContentInfo *cms, BIO *icont) return NULL; } - + int CMS_dataFinal(CMS_ContentInfo *cms, BIO *cmsbio) { ASN1_OCTET_STRING **pos = CMS_get0_content(cms); diff --git a/crypto/cms/cms_smime.c b/crypto/cms/cms_smime.c index 0a67c78694..a1ee0f24e2 100644 --- a/crypto/cms/cms_smime.c +++ b/crypto/cms/cms_smime.c @@ -188,6 +188,40 @@ CMS_ContentInfo *CMS_digest_create(BIO *in, const EVP_MD *md, return NULL; } +int CMS_EncryptedData_decrypt(CMS_ContentInfo *cms, + const unsigned char *key, size_t keylen, + BIO *dcont, BIO *out, unsigned int flags) + { + BIO *cont; + int r; + if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_encrypted) + { + CMSerr(CMS_F_CMS_ENCRYPTEDDATA_DECRYPT, + CMS_R_TYPE_NOT_ENCRYPTED_DATA); + return 0; + } + + if (!dcont) + { + ASN1_OCTET_STRING **pos = CMS_get0_content(cms); + if (!pos || !*pos) + { + CMSerr(CMS_F_CMS_ENCRYPTEDDATA_DECRYPT, + CMS_R_NO_CONTENT); + return 0; + } + } + + cont = CMS_dataInit(cms, dcont); + if (!cont) + return 0; + r = CMS_EncryptedData_set1_key(cont, cms, key, keylen); + if (r) + r = cms_copy_content(out, cont, flags); + BIO_free_all(cont); + return r; + } + static int cms_signerinfo_verify_cert(CMS_SignerInfo *si, X509_STORE *store, STACK_OF(X509) *certs, diff --git a/test/runex.pl b/test/runex.pl index 1c7431b865..ff21f90702 100644 --- a/test/runex.pl +++ b/test/runex.pl @@ -77,10 +77,12 @@ my @test_list = ( ["5.1.bin" => "encode"], ["5.2.bin" => "encode"], ["6.0.bin" => "encode, digest, cont"], -["7.1.bin" => "encode"], -["7.2.bin" => "encode"] +["7.1.bin" => "encode, encrypted, cont"], +["7.2.bin" => "encode, encrypted, cont"] ); +my $secretkey = "73:7c:79:1f:25:ea:d0:e0:46:29:25:43:52:f7:dc:62:91:e5:cb:26:91:7a:da:32"; + if (!-d $exdir) { print STDERR "FATAL ERROR: examples directory missing!!\n"; @@ -111,6 +113,10 @@ foreach (@test_list) { { run_digest_test($exdir, $tlist, $file); } + if ($tlist =~ /encrypted/) + { + run_encrypted_test($exdir, $tlist, $file, $secretkey); + } } @@ -234,6 +240,32 @@ sub run_digest_test } } +sub run_encrypted_test + { + my ($cmsdir, $tlist, $tfile, $key) = @_; + unlink "tmp.txt"; + + system ("$cmscmd -EncrypedData_decrypt -inform DER" . + " -secretkey $key" . + " -in $cmsdir/$tfile -out tmp.txt"); + + if ($?) + { + print "\tEncrypted Data command FAILED!!\n"; + $badtest++; + } + elsif ($tlist =~ /cont/ && + !cmp_files("$cmsdir/ExContent.bin", "tmp.txt")) + { + print "\tEncrypted Data content compare FAILED!!\n"; + $badtest++; + } + else + { + print "\tEncryptedData verify passed\n" if $verbose; + } + } + sub cmp_files { my ($f1, $f2) = @_; -- 2.25.1