PROV & SERIALIZER: Adapt the RSA serializers for PSS-parameters
[openssl.git] / providers / implementations / serializers / serializer_rsa.c
index 21898f9e3d4355bbba978940c70d4bbe07ec2489..564210ede245389e43a46841e0173e6ad9159192 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the Apache License 2.0 (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
  */
 #include "internal/deprecated.h"
 
+#include "internal/packet.h"
 #include "crypto/rsa.h"           /* rsa_get0_all_params() */
 #include "prov/bio.h"             /* ossl_prov_bio_printf() */
+#include "prov/der_rsa.h"         /* DER_w_RSASSA_PSS_params() */
 #include "prov/implementations.h" /* rsa_keymgmt_functions */
 #include "serializer_local.h"
 
@@ -43,6 +45,7 @@ int ossl_prov_print_rsa(BIO *out, RSA *rsa, int priv)
     STACK_OF(BIGNUM_const) *factors = sk_BIGNUM_const_new_null();
     STACK_OF(BIGNUM_const) *exps = sk_BIGNUM_const_new_null();
     STACK_OF(BIGNUM_const) *coeffs = sk_BIGNUM_const_new_null();
+    RSA_PSS_PARAMS_30 *pss_params = rsa_get0_pss_params_30(rsa);
     int ret = 0;
 
     if (rsa == NULL || factors == NULL || exps == NULL || coeffs == NULL)
@@ -109,6 +112,61 @@ int ossl_prov_print_rsa(BIO *out, RSA *rsa, int priv)
                 goto err;
         }
     }
+
+    switch (RSA_test_flags(rsa, RSA_FLAG_TYPE_MASK)) {
+    case RSA_FLAG_TYPE_RSA:
+        if (!rsa_pss_params_30_is_unrestricted(pss_params)) {
+            if (ossl_prov_bio_printf(out, "(INVALID PSS PARAMETERS)\n") <= 0)
+                goto err;
+        }
+        break;
+    case RSA_FLAG_TYPE_RSASSAPSS:
+        if (rsa_pss_params_30_is_unrestricted(pss_params)) {
+            if (ossl_prov_bio_printf(out,
+                                     "No PSS parameter restrictions\n") <= 0)
+                goto err;
+        } else {
+            int hashalg_nid = rsa_pss_params_30_hashalg(pss_params);
+            int maskgenalg_nid = rsa_pss_params_30_maskgenalg(pss_params);
+            int maskgenhashalg_nid =
+                rsa_pss_params_30_maskgenhashalg(pss_params);
+            int saltlen = rsa_pss_params_30_saltlen(pss_params);
+            int trailerfield = rsa_pss_params_30_trailerfield(pss_params);
+
+            if (ossl_prov_bio_printf(out, "PSS parameter restrictions:\n") <= 0)
+                goto err;
+            if (ossl_prov_bio_printf(out, "  Hash Algorithm: %s%s\n",
+                                     rsa_oaeppss_nid2name(hashalg_nid),
+                                     (hashalg_nid == NID_sha1
+                                      ? " (default)" : "")) <= 0)
+                goto err;
+            if (ossl_prov_bio_printf(out, "  Mask Algorithm: %s with %s%s\n",
+                                     rsa_mgf_nid2name(maskgenalg_nid),
+                                     rsa_oaeppss_nid2name(maskgenhashalg_nid),
+                                     (maskgenalg_nid == NID_mgf1
+                                      && maskgenhashalg_nid == NID_sha1
+                                      ? " (default)" : "")) <= 0)
+                goto err;
+            if (ossl_prov_bio_printf(out, "  Minimum Salt Length: %d%s\n",
+                                     saltlen,
+                                     (saltlen == 20 ? " (default)" : "")) <= 0)
+                goto err;
+            /*
+             * TODO(3.0) Should we show the ASN.1 trailerField value, or
+             * the actual trailerfield byte (i.e. 0xBC for 1)?
+             * crypto/rsa/rsa_ameth.c isn't very clear on that, as it
+             * does display 0xBC when the default applies, but the ASN.1
+             * trailerField value otherwise...
+             */
+            if (ossl_prov_bio_printf(out, "  Trailer Field: 0x%x%s\n",
+                                     trailerfield,
+                                     (trailerfield == 1 ? " (default)" : ""))
+                <= 0)
+                goto err;
+        }
+        break;
+    }
+
     ret = 1;
  err:
     sk_BIGNUM_const_free(factors);
@@ -116,3 +174,90 @@ int ossl_prov_print_rsa(BIO *out, RSA *rsa, int priv)
     sk_BIGNUM_const_free(coeffs);
     return ret;
 }
+
+/*
+ * Helper functions to prepare RSA-PSS params for serialization.  We would
+ * have simply written the whole AlgorithmIdentifier, but existing libcrypto
+ * functionality doesn't allow that.
+ */
+
+int ossl_prov_prepare_rsa_params(const void *rsa, int nid,
+                                 void **pstr, int *pstrtype)
+{
+    const RSA_PSS_PARAMS_30 *pss = rsa_get0_pss_params_30((RSA *)rsa);
+
+    *pstr = NULL;
+
+    switch (RSA_test_flags(rsa, RSA_FLAG_TYPE_MASK)) {
+    case RSA_FLAG_TYPE_RSA:
+        /* If plain RSA, the parameters shall be NULL */
+        *pstrtype = V_ASN1_NULL;
+        return 1;
+    case RSA_FLAG_TYPE_RSASSAPSS:
+        if (rsa_pss_params_30_is_unrestricted(pss)) {
+            *pstrtype = V_ASN1_UNDEF;
+        } else {
+            ASN1_STRING *astr = NULL;
+            WPACKET pkt;
+            unsigned char *str = NULL;
+            size_t str_sz = 0;
+            int i;
+
+            for (i = 0; i < 2; i++) {
+                switch (i) {
+                case 0:
+                    if (!WPACKET_init_null_der(&pkt))
+                        goto err;
+                    break;
+                case 1:
+                    if ((str = OPENSSL_malloc(str_sz)) == NULL
+                        || !WPACKET_init_der(&pkt, str, str_sz)) {
+                        goto err;
+                    }
+                    break;
+                }
+                if (!DER_w_RSASSA_PSS_params(&pkt, -1, pss)
+                    || !WPACKET_finish(&pkt))
+                    goto err;
+                WPACKET_get_total_written(&pkt, &str_sz);
+                WPACKET_cleanup(&pkt);
+
+                /*
+                 * If no PSS parameters are going to be written, there's no
+                 * point going for another iteration.
+                 * This saves us from getting |str| allocated just to have it
+                 * immediately de-allocated.
+                 */
+                if (str_sz == 0)
+                    break;
+            }
+
+            if ((astr = ASN1_STRING_new()) == NULL)
+                goto err;
+            *pstrtype = V_ASN1_SEQUENCE;
+            ASN1_STRING_set0(astr, str, (int)str_sz);
+            *pstr = astr;
+
+            return 1;
+         err:
+            OPENSSL_free(str);
+            return 0;
+        }
+    }
+
+    /* Currently unsupported RSA key type */
+    return 0;
+}
+
+int ossl_prov_rsa_type_to_evp(const RSA *rsa)
+{
+    switch (RSA_test_flags(rsa, RSA_FLAG_TYPE_MASK)) {
+    case RSA_FLAG_TYPE_RSA:
+        return EVP_PKEY_RSA;
+    case RSA_FLAG_TYPE_RSASSAPSS:
+        return EVP_PKEY_RSA_PSS;
+    }
+
+    /* Currently unsupported RSA key type */
+    return EVP_PKEY_NONE;
+}