PROV & SERIALIZER: Adapt the RSA serializers for PSS-parameters
authorRichard Levitte <levitte@openssl.org>
Sat, 2 May 2020 11:39:40 +0000 (13:39 +0200)
committerRichard Levitte <levitte@openssl.org>
Thu, 14 May 2020 10:16:35 +0000 (12:16 +0200)
Reviewed-by: Shane Lontis <shane.lontis@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/11710)

providers/defltprov.c
providers/implementations/serializers/build.info
providers/implementations/serializers/serializer_local.h
providers/implementations/serializers/serializer_rsa.c
providers/implementations/serializers/serializer_rsa_priv.c
providers/implementations/serializers/serializer_rsa_pub.c

index 68a1a2b..cedbddb 100644 (file)
@@ -392,6 +392,18 @@ static const OSSL_ALGORITHM deflt_serializer[] = {
       rsa_priv_pem_serializer_functions },
     { "RSA", "provider=default,fips=yes,format=pem,type=public",
       rsa_pub_pem_serializer_functions },
+    { "RSA-PSS", "provider=default,fips=yes,format=text,type=private",
+      rsa_priv_text_serializer_functions },
+    { "RSA-PSS", "provider=default,fips=yes,format=text,type=public",
+      rsa_pub_text_serializer_functions },
+    { "RSA-PSS", "provider=default,fips=yes,format=der,type=private",
+      rsa_priv_der_serializer_functions },
+    { "RSA-PSS", "provider=default,fips=yes,format=der,type=public",
+      rsa_pub_der_serializer_functions },
+    { "RSA-PSS", "provider=default,fips=yes,format=pem,type=private",
+      rsa_priv_pem_serializer_functions },
+    { "RSA-PSS", "provider=default,fips=yes,format=pem,type=public",
+      rsa_pub_pem_serializer_functions },
 
 #ifndef OPENSSL_NO_DH
     { "DH", "provider=default,fips=yes,format=text,type=private",
index 097bdca..ffafbe3 100644 (file)
@@ -10,7 +10,10 @@ $ECX_GOAL=../../libimplementations.a
 $EC_GOAL=../../libimplementations.a
 
 SOURCE[$SERIALIZER_GOAL]=serializer_common.c
+
 SOURCE[$RSA_GOAL]=serializer_rsa.c serializer_rsa_priv.c serializer_rsa_pub.c
+DEPEND[serializer_rsa.o]=../../common/include/prov/der_rsa.h
+
 IF[{- !$disabled{"dh"} || !$disabled{"dsa"} -}]
   SOURCE[$FFC_GOAL]=serializer_ffc_params.c
 ENDIF
index 39fb3ab..f4aee6f 100644 (file)
@@ -82,6 +82,14 @@ int ossl_prov_prepare_all_dsa_params(const void *dsa, int nid,
 int ossl_prov_dsa_pub_to_der(const void *dsa, unsigned char **pder);
 int ossl_prov_dsa_priv_to_der(const void *dsa, unsigned char **pder);
 
+/*
+ * ossl_prov_prepare_rsa_params() is designed to work with the ossl_prov_write_
+ * functions, hence 'void *rsa' rather than 'RSA *rsa'.
+ */
+int ossl_prov_prepare_rsa_params(const void *rsa, int nid,
+                                 void **pstr, int *pstrtype);
+int ossl_prov_rsa_type_to_evp(const RSA *rsa);
+
 int ossl_prov_print_labeled_bignum(BIO *out, const char *label,
                                    const BIGNUM *bn);
 int ossl_prov_print_labeled_buf(BIO *out, const char *label,
index 7578fec..564210e 100644 (file)
  */
 #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;
+}
index 8196473..8c68f5d 100644 (file)
@@ -21,6 +21,7 @@
 #include <openssl/types.h>
 #include <openssl/params.h>
 #include <openssl/safestack.h>
+#include "crypto/rsa.h"
 #include "prov/bio.h"
 #include "prov/implementations.h"
 #include "prov/providercommonerr.h"
@@ -49,34 +50,6 @@ struct rsa_priv_ctx_st {
     struct pkcs8_encrypt_ctx_st sc;
 };
 
-/* Helper functions to prepare RSA-PSS params for serialization */
-
-static int prepare_rsa_params(const void *rsa, int nid,
-                              void **pstr, int *pstrtype)
-{
-    const RSA_PSS_PARAMS *pss = RSA_get0_pss_params(rsa);
-    *pstr = NULL;
-
-    /* If RSA it's just NULL type */
-    if (nid != EVP_PKEY_RSA_PSS) {
-        *pstrtype = V_ASN1_NULL;
-        return 1;
-    }
-    /* If no PSS parameters we omit parameters entirely */
-    if (pss == NULL) {
-        *pstrtype = V_ASN1_UNDEF;
-        return 1;
-    }
-    /* Encode PSS parameters */
-    if (ASN1_item_pack((void *)pss, ASN1_ITEM_rptr(RSA_PSS_PARAMS),
-                       (ASN1_STRING **)pstr)
-        == NULL)
-        return 0;
-
-    *pstrtype = V_ASN1_SEQUENCE;
-    return 1;
-}
-
 /* Private key : context */
 static void *rsa_priv_newctx(void *provctx)
 {
@@ -176,8 +149,9 @@ static int rsa_priv_der(void *vctx, void *rsa, BIO *out,
     ctx->sc.cb = cb;
     ctx->sc.cbarg = cbarg;
 
-    ret = ossl_prov_write_priv_der_from_obj(out, rsa, EVP_PKEY_RSA,
-                                            prepare_rsa_params,
+    ret = ossl_prov_write_priv_der_from_obj(out, rsa,
+                                            ossl_prov_rsa_type_to_evp(rsa),
+                                            ossl_prov_prepare_rsa_params,
                                             (i2d_of_void *)i2d_RSAPrivateKey,
                                             &ctx->sc);
 
@@ -215,8 +189,9 @@ static int rsa_pem_priv(void *vctx, void *rsa, BIO *out,
     ctx->sc.cb = cb;
     ctx->sc.cbarg = cbarg;
 
-    ret = ossl_prov_write_priv_pem_from_obj(out, rsa, EVP_PKEY_RSA,
-                                            prepare_rsa_params,
+    ret = ossl_prov_write_priv_pem_from_obj(out, rsa,
+                                            ossl_prov_rsa_type_to_evp(rsa),
+                                            ossl_prov_prepare_rsa_params,
                                             (i2d_of_void *)i2d_RSAPrivateKey,
                                             &ctx->sc);
 
index bcae074..28df008 100644 (file)
@@ -72,7 +72,10 @@ static int rsa_pub_der_data(void *ctx, const OSSL_PARAM params[], BIO *out,
 static int rsa_pub_der(void *ctx, void *rsa, BIO *out,
                        OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg)
 {
-    return i2d_RSA_PUBKEY_bio(out, rsa);
+    return ossl_prov_write_pub_der_from_obj(out, rsa,
+                                            ossl_prov_rsa_type_to_evp(rsa),
+                                            ossl_prov_prepare_rsa_params,
+                                            (i2d_of_void *)i2d_RSAPublicKey);
 }
 
 /* Public key : PEM */
@@ -100,7 +103,10 @@ static int rsa_pub_pem_data(void *ctx, const OSSL_PARAM params[], BIO *out,
 static int rsa_pub_pem(void *ctx, void *rsa, BIO *out,
                        OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg)
 {
-    return PEM_write_bio_RSA_PUBKEY(out, rsa);
+    return ossl_prov_write_pub_pem_from_obj(out, rsa,
+                                            ossl_prov_rsa_type_to_evp(rsa),
+                                            ossl_prov_prepare_rsa_params,
+                                            (i2d_of_void *)i2d_RSAPublicKey);
 }
 
 static int rsa_pub_print_data(void *ctx, const OSSL_PARAM params[], BIO *out,