Allow digests to supply S/MIME micalg values from a ctrl.
[openssl.git] / crypto / pkcs7 / pk7_mime.c
index 134746c1864f4da4461cfb271b0b29fc6bea95aa..01bd59fa6979a1bf1a2d1545ccd8fff4351aeb84 100644 (file)
@@ -144,6 +144,87 @@ static PKCS7 *B64_read_PKCS7(BIO *bio)
        return p7;
 }
 
+/* Generate the MIME "micalg" parameter from RFC3851, RFC4490 */
+
+static int pk7_write_micalg(BIO *out, PKCS7 *p7)
+       {
+       STACK_OF(X509_ALGOR) *mdalgs;
+       const EVP_MD *md;
+       int i, have_unknown = 0, write_comma, ret = 0, md_nid;
+       mdalgs = p7->d.sign->md_algs;
+       have_unknown = 0;
+       write_comma = 0;
+       for (i = 0; i < sk_X509_ALGOR_num(mdalgs); i++)
+               {
+               if (write_comma)
+                       BIO_write(out, ",", 1);
+               write_comma = 1;
+               md_nid = OBJ_obj2nid(sk_X509_ALGOR_value(mdalgs, i)->algorithm);
+               md = EVP_get_digestbynid(md_nid);
+               if (md && md->md_ctrl)
+                       {
+                       int rv;
+                       char *micstr;
+                       rv = md->md_ctrl(NULL, EVP_MD_CTRL_MICALG, 0, &micstr);
+                       if (rv > 0)
+                               {
+                               BIO_puts(out, micstr);
+                               OPENSSL_free(micstr);
+                               continue;
+                               }
+                       if (rv != -2)
+                               goto err;
+                       }
+               switch(md_nid)
+                       {
+                       case NID_sha1:
+                       BIO_puts(out, "sha1");
+                       break;
+
+                       case NID_md5:
+                       BIO_puts(out, "md5");
+                       break;
+
+                       case NID_sha256:
+                       BIO_puts(out, "sha-256");
+                       break;
+
+                       case NID_sha384:
+                       BIO_puts(out, "sha-384");
+                       break;
+
+                       case NID_sha512:
+                       BIO_puts(out, "sha-512");
+                       break;
+
+                       case NID_id_GostR3411_94:
+                       BIO_puts(out, "gostr3411-94");
+                               goto err;
+                       break;
+
+                       default:
+                       if (have_unknown)
+                               write_comma = 0;
+                       else
+                               {
+                               BIO_puts(out, "unknown");
+                               have_unknown = 1;
+                               }
+                       break;
+
+                       }
+               }
+
+       ret = 1;
+       err:
+
+       return ret;
+
+       }
+
+
+
+
 /* SMIME sender */
 
 int SMIME_write_PKCS7(BIO *bio, PKCS7 *p7, BIO *data, int flags)
@@ -174,7 +255,9 @@ int SMIME_write_PKCS7(BIO *bio, PKCS7 *p7, BIO *data, int flags)
                BIO_printf(bio, "MIME-Version: 1.0%s", mime_eol);
                BIO_printf(bio, "Content-Type: multipart/signed;");
                BIO_printf(bio, " protocol=\"%ssignature\";", mime_prefix);
-               BIO_printf(bio, " micalg=sha1; boundary=\"----%s\"%s%s",
+               BIO_puts(bio, " micalg=\"");
+               pk7_write_micalg(bio, p7);
+               BIO_printf(bio, "\"; boundary=\"----%s\"%s%s",
                                                bound, mime_eol, mime_eol);
                BIO_printf(bio, "This is an S/MIME signed message%s%s",
                                                mime_eol, mime_eol);
@@ -204,7 +287,7 @@ int SMIME_write_PKCS7(BIO *bio, PKCS7 *p7, BIO *data, int flags)
                msg_type = "enveloped-data";
        else if (PKCS7_type_is_signed(p7))
                {
-               /* If we have any signers it is signed-data othewise 
+               /* If we have any signers it is signed-data otherwise 
                 * certs-only.
                 */
                STACK_OF(PKCS7_SIGNER_INFO) *sinfos;