summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/abstract_int.h23
-rw-r--r--lib/algorithms/publickey.c1
-rw-r--r--lib/algorithms/sign.c11
-rw-r--r--lib/crypto-backend.h21
-rw-r--r--lib/gnutls.asn8
-rw-r--r--lib/gnutls_asn1_tab.c13
-rw-r--r--lib/gnutls_int.h2
-rw-r--r--lib/includes/gnutls/abstract.h7
-rw-r--r--lib/includes/gnutls/gnutls.h.in13
-rw-r--r--lib/includes/gnutls/x509.h30
-rw-r--r--lib/libgnutls.map13
-rw-r--r--lib/nettle/pk.c219
-rw-r--r--lib/opencdk/pubkey.c2
-rw-r--r--lib/openpgp/privkey.c2
-rw-r--r--lib/pk.c23
-rw-r--r--lib/pk.h7
-rw-r--r--lib/privkey.c157
-rw-r--r--lib/pubkey.c116
-rw-r--r--lib/x509/Makefile.am1
-rw-r--r--lib/x509/common.c39
-rw-r--r--lib/x509/common.h2
-rw-r--r--lib/x509/crl.c23
-rw-r--r--lib/x509/crl_write.c2
-rw-r--r--lib/x509/crq.c184
-rw-r--r--lib/x509/key_decode.c171
-rw-r--r--lib/x509/key_encode.c115
-rw-r--r--lib/x509/mpi.c122
-rw-r--r--lib/x509/output.c112
-rw-r--r--lib/x509/pkcs7.c30
-rw-r--r--lib/x509/privkey.c117
-rw-r--r--lib/x509/privkey_pkcs8.c41
-rw-r--r--lib/x509/sign.c76
-rw-r--r--lib/x509/spki.c188
-rw-r--r--lib/x509/verify.c134
-rw-r--r--lib/x509/x509.c56
-rw-r--r--lib/x509/x509_int.h40
-rw-r--r--lib/x509/x509_write.c102
37 files changed, 2052 insertions, 171 deletions
diff --git a/lib/abstract_int.h b/lib/abstract_int.h
index 3693d00074..ac582180d7 100644
--- a/lib/abstract_int.h
+++ b/lib/abstract_int.h
@@ -82,8 +82,25 @@ struct gnutls_pubkey_st {
int _gnutls_privkey_get_public_mpis(gnutls_privkey_t key,
gnutls_pk_params_st *);
+int _gnutls_privkey_get_sign_params(gnutls_privkey_t key,
+ gnutls_x509_spki_st * params);
+int _gnutls_privkey_find_sign_params(gnutls_privkey_t key,
+ gnutls_pk_algorithm_t pk,
+ gnutls_digest_algorithm_t dig,
+ unsigned flags,
+ gnutls_x509_spki_st *params);
+
void _gnutls_privkey_cleanup(gnutls_privkey_t key);
+int privkey_sign_data(gnutls_privkey_t signer,
+ const gnutls_datum_t * data,
+ gnutls_datum_t * signature,
+ gnutls_x509_spki_st *params);
+int privkey_sign_hash(gnutls_privkey_t signer,
+ const gnutls_datum_t * hash_data,
+ gnutls_datum_t * signature,
+ gnutls_x509_spki_st * params);
+
unsigned pubkey_to_bits(gnutls_pk_algorithm_t pk, gnutls_pk_params_st * params);
int _gnutls_pubkey_compatible_with_sig(gnutls_session_t,
gnutls_pubkey_t pubkey,
@@ -97,13 +114,15 @@ pubkey_verify_hashed_data(gnutls_pk_algorithm_t pk,
const mac_entry_st * algo,
const gnutls_datum_t * hash,
const gnutls_datum_t * signature,
- gnutls_pk_params_st * issuer_params);
+ gnutls_pk_params_st * params,
+ gnutls_x509_spki_st * sign_params);
int pubkey_verify_data(gnutls_pk_algorithm_t pk,
const mac_entry_st * algo,
const gnutls_datum_t * data,
const gnutls_datum_t * signature,
- gnutls_pk_params_st * issuer_params);
+ gnutls_pk_params_st * params,
+ gnutls_x509_spki_st * sign_params);
diff --git a/lib/algorithms/publickey.c b/lib/algorithms/publickey.c
index 5ef780986f..aba3896004 100644
--- a/lib/algorithms/publickey.c
+++ b/lib/algorithms/publickey.c
@@ -89,6 +89,7 @@ static const gnutls_pk_entry pk_algorithms[] = {
* we want to return OID from is first */
{"UNKNOWN", NULL, GNUTLS_PK_UNKNOWN},
{"RSA", PK_PKIX1_RSA_OID, GNUTLS_PK_RSA},
+ {"RSA-PSS", PK_PKIX1_RSA_PSS_OID, GNUTLS_PK_RSA_PSS},
{"RSA (X.509)", PK_X509_RSA_OID, GNUTLS_PK_RSA}, /* some certificates use this OID for RSA */
{"RSA-MD5", SIG_RSA_MD5_OID, GNUTLS_PK_RSA}, /* some other broken certificates set RSA with MD5 as an indicator of RSA */
{"RSA-SHA1", SIG_RSA_SHA1_OID, GNUTLS_PK_RSA}, /* some other broken certificates set RSA with SHA1 as an indicator of RSA */
diff --git a/lib/algorithms/sign.c b/lib/algorithms/sign.c
index 6107c44435..614b17155e 100644
--- a/lib/algorithms/sign.c
+++ b/lib/algorithms/sign.c
@@ -123,6 +123,17 @@ static const gnutls_sign_entry sign_algorithms[] = {
GNUTLS_PK_DSA, GNUTLS_DIG_SHA3_384, TLS_SIGN_AID_UNKNOWN},
{"DSA-SHA3-512", SIG_DSA_SHA3_512_OID, GNUTLS_SIGN_DSA_SHA3_512,
GNUTLS_PK_DSA, GNUTLS_DIG_SHA3_512, TLS_SIGN_AID_UNKNOWN},
+
+ {"RSA-PSS-SHA256", PK_PKIX1_RSA_PSS_OID, GNUTLS_SIGN_RSA_PSS_SHA256,
+ GNUTLS_PK_RSA_PSS,
+ GNUTLS_DIG_SHA256, {8, 4}},
+ {"RSA-PSS-SHA384", PK_PKIX1_RSA_PSS_OID, GNUTLS_SIGN_RSA_PSS_SHA384,
+ GNUTLS_PK_RSA_PSS,
+ GNUTLS_DIG_SHA384, {8, 5}},
+ {"RSA-PSS-SHA512", PK_PKIX1_RSA_PSS_OID, GNUTLS_SIGN_RSA_PSS_SHA512,
+ GNUTLS_PK_RSA_PSS,
+ GNUTLS_DIG_SHA512, {8, 6}},
+
{0, 0, 0, 0, 0, TLS_SIGN_AID_UNKNOWN}
};
diff --git a/lib/crypto-backend.h b/lib/crypto-backend.h
index 1f0b85fb11..d60a5745c2 100644
--- a/lib/crypto-backend.h
+++ b/lib/crypto-backend.h
@@ -166,6 +166,20 @@ typedef struct gnutls_crypto_bigint {
gnutls_bigint_format_t format);
} gnutls_crypto_bigint_st;
+/* additional information about the public key
+ */
+typedef struct gnutls_x509_spki_st {
+ gnutls_pk_algorithm_t pk;
+ gnutls_digest_algorithm_t dig;
+
+ /* the size of salt used by RSA-PSS */
+ unsigned int salt_size;
+
+ /* if non-zero, the legacy value for PKCS#7 signatures will be
+ * written for RSA signatures. */
+ unsigned int legacy;
+} gnutls_x509_spki_st;
+
#define GNUTLS_MAX_PK_PARAMS 16
typedef struct {
@@ -178,6 +192,7 @@ typedef struct {
unsigned int seed_size;
uint8_t seed[MAX_PVP_SEED_SIZE];
gnutls_digest_algorithm_t palgo;
+ gnutls_x509_spki_st sign;
gnutls_pk_algorithm_t algo;
} gnutls_pk_params_st;
@@ -314,10 +329,12 @@ typedef struct gnutls_crypto_pk {
int (*sign) (gnutls_pk_algorithm_t, gnutls_datum_t * signature,
const gnutls_datum_t * data,
- const gnutls_pk_params_st * priv);
+ const gnutls_pk_params_st *priv,
+ const gnutls_x509_spki_st *sign);
int (*verify) (gnutls_pk_algorithm_t, const gnutls_datum_t * data,
const gnutls_datum_t * sig,
- const gnutls_pk_params_st * pub);
+ const gnutls_pk_params_st *pub,
+ const gnutls_x509_spki_st *sign);
/* sanity checks the public key parameters */
int (*verify_priv_params) (gnutls_pk_algorithm_t,
const gnutls_pk_params_st * priv);
diff --git a/lib/gnutls.asn b/lib/gnutls.asn
index cce748d52b..e006b6d5b7 100644
--- a/lib/gnutls.asn
+++ b/lib/gnutls.asn
@@ -118,4 +118,12 @@ KRB5PrincipalName ::= SEQUENCE {
principalName [1] PrincipalName
}
+-- from RFC4055
+RSAPSSParameters ::= SEQUENCE {
+ hashAlgorithm [0] AlgorithmIdentifier OPTIONAL, -- sha1Identifier
+ maskGenAlgorithm [1] AlgorithmIdentifier OPTIONAL, -- mgf1SHA1Identifier
+ saltLength [2] INTEGER DEFAULT 20,
+ trailerField [3] INTEGER DEFAULT 1
+}
+
END
diff --git a/lib/gnutls_asn1_tab.c b/lib/gnutls_asn1_tab.c
index 4d69728163..587e54ed36 100644
--- a/lib/gnutls_asn1_tab.c
+++ b/lib/gnutls_asn1_tab.c
@@ -79,10 +79,21 @@ const asn1_static_node gnutls_asn1_tab[] = {
{ "name-string", 536879115, NULL },
{ NULL, 1073743880, "1"},
{ NULL, 27, NULL },
- { "KRB5PrincipalName", 536870917, NULL },
+ { "KRB5PrincipalName", 1610612741, NULL },
{ "realm", 1610620955, NULL },
{ NULL, 2056, "0"},
{ "principalName", 536879106, "PrincipalName"},
{ NULL, 2056, "1"},
+ { "RSAPSSParameters", 536870917, NULL },
+ { "hashAlgorithm", 1610637314, "AlgorithmIdentifier"},
+ { NULL, 2056, "0"},
+ { "maskGenAlgorithm", 1610637314, "AlgorithmIdentifier"},
+ { NULL, 2056, "1"},
+ { "saltLength", 1610653699, NULL },
+ { NULL, 1073741833, "20"},
+ { NULL, 2056, "2"},
+ { "trailerField", 536911875, NULL },
+ { NULL, 1073741833, "1"},
+ { NULL, 2056, "3"},
{ NULL, 0, NULL }
};
diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h
index 5d013c83c2..28adae80a8 100644
--- a/lib/gnutls_int.h
+++ b/lib/gnutls_int.h
@@ -293,6 +293,8 @@ typedef enum content_type_t {
#define GNUTLS_PK_ANY (gnutls_pk_algorithm_t)-1
#define GNUTLS_PK_NONE (gnutls_pk_algorithm_t)-2
+#define GNUTLS_PK_IS_RSA(pk) ((pk) == GNUTLS_PK_RSA || (pk) == GNUTLS_PK_RSA_PSS)
+
/* Message buffers (mbuffers) structures */
/* this is actually the maximum number of distinct handshake
diff --git a/lib/includes/gnutls/abstract.h b/lib/includes/gnutls/abstract.h
index e4c3efd42c..dec5db4e3f 100644
--- a/lib/includes/gnutls/abstract.h
+++ b/lib/includes/gnutls/abstract.h
@@ -52,6 +52,7 @@ typedef enum gnutls_pubkey_flags {
} gnutls_pubkey_flags_t;
#define GNUTLS_PUBKEY_VERIFY_FLAG_TLS1_RSA GNUTLS_VERIFY_USE_TLS1_RSA
+#define GNUTLS_PUBKEY_VERIFY_FLAG_RSA_PSS GNUTLS_VERIFY_USE_RSA_PSS
typedef int (*gnutls_privkey_sign_func) (gnutls_privkey_t key,
void *userdata,
@@ -267,6 +268,8 @@ int gnutls_privkey_status(gnutls_privkey_t key);
/**
* gnutls_privkey_flags:
* @GNUTLS_PRIVKEY_SIGN_FLAG_TLS1_RSA: Make an RSA signature on the hashed data as in the TLS protocol.
+ * @GNUTLS_PRIVKEY_SIGN_FLAG_RSA_PSS: Make an RSA signature on the hashed data with the PSS padding.
+ * @GNUTLS_PRIVKEY_SIGN_FLAG_REPRODUCIBLE: Make an RSA-PSS signature on the hashed data with reproducible parameters (zero salt).
* @GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE: When importing a private key, automatically
* release it when the structure it was imported is released.
* @GNUTLS_PRIVKEY_IMPORT_COPY: Copy required values during import.
@@ -285,7 +288,9 @@ typedef enum gnutls_privkey_flags {
GNUTLS_PRIVKEY_DISABLE_CALLBACKS = 1 << 2,
GNUTLS_PRIVKEY_SIGN_FLAG_TLS1_RSA = 1 << 4,
GNUTLS_PRIVKEY_FLAG_PROVABLE = 1 << 5,
- GNUTLS_PRIVKEY_FLAG_EXPORT_COMPAT = 1 << 6
+ GNUTLS_PRIVKEY_FLAG_EXPORT_COMPAT = 1 << 6,
+ GNUTLS_PRIVKEY_SIGN_FLAG_RSA_PSS = 1 << 7,
+ GNUTLS_PRIVKEY_SIGN_FLAG_REPRODUCIBLE = GNUTLS_PRIVKEY_FLAG_PROVABLE /* save a flag, they are not overlapping */
} gnutls_privkey_flags_t;
int gnutls_privkey_import_pkcs11(gnutls_privkey_t pkey,
diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in
index 580cf9f00c..19dc4f252b 100644
--- a/lib/includes/gnutls/gnutls.h.in
+++ b/lib/includes/gnutls/gnutls.h.in
@@ -701,6 +701,7 @@ typedef enum gnutls_certificate_print_formats {
* gnutls_pk_algorithm_t:
* @GNUTLS_PK_UNKNOWN: Unknown public-key algorithm.
* @GNUTLS_PK_RSA: RSA public-key algorithm.
+ * @GNUTLS_PK_RSA_PSS: RSA public-key algorithm, with PSS padding.
* @GNUTLS_PK_DSA: DSA public-key algorithm.
* @GNUTLS_PK_DH: Diffie-Hellman algorithm. Used to generate parameters.
* @GNUTLS_PK_ECDSA: Elliptic curve algorithm. These parameters are compatible with the ECDSA and ECDH algorithm.
@@ -715,7 +716,8 @@ typedef enum {
GNUTLS_PK_DH = 3,
GNUTLS_PK_ECDSA = 4,
GNUTLS_PK_ECDHX = 5,
- GNUTLS_PK_MAX = GNUTLS_PK_ECDHX
+ GNUTLS_PK_RSA_PSS = 6,
+ GNUTLS_PK_MAX = GNUTLS_PK_RSA_PSS
} gnutls_pk_algorithm_t;
@@ -756,6 +758,9 @@ const char *gnutls_pk_algorithm_get_name(gnutls_pk_algorithm_t algorithm);
* @GNUTLS_SIGN_RSA_SHA3_256: Digital signature algorithm RSA with SHA3-256.
* @GNUTLS_SIGN_RSA_SHA3_384: Digital signature algorithm RSA with SHA3-384.
* @GNUTLS_SIGN_RSA_SHA3_512: Digital signature algorithm RSA with SHA3-512.
+ * @GNUTLS_SIGN_RSA_PSS_SHA256: Digital signature algorithm RSA with SHA-256, with PSS padding.
+ * @GNUTLS_SIGN_RSA_PSS_SHA384: Digital signature algorithm RSA with SHA-384, with PSS padding.
+ * @GNUTLS_SIGN_RSA_PSS_SHA512: Digital signature algorithm RSA with SHA-512, with PSS padding.
*
* Enumeration of different digital signature algorithms.
*/
@@ -794,7 +799,11 @@ typedef enum {
GNUTLS_SIGN_RSA_SHA3_256 = 29,
GNUTLS_SIGN_RSA_SHA3_384 = 30,
GNUTLS_SIGN_RSA_SHA3_512 = 31,
- GNUTLS_SIGN_MAX = GNUTLS_SIGN_RSA_SHA3_512
+
+ GNUTLS_SIGN_RSA_PSS_SHA256 = 32,
+ GNUTLS_SIGN_RSA_PSS_SHA384 = 33,
+ GNUTLS_SIGN_RSA_PSS_SHA512 = 34,
+ GNUTLS_SIGN_MAX = GNUTLS_SIGN_RSA_PSS_SHA512
} gnutls_sign_algorithm_t;
/**
diff --git a/lib/includes/gnutls/x509.h b/lib/includes/gnutls/x509.h
index 4646299368..cc30a5fd6c 100644
--- a/lib/includes/gnutls/x509.h
+++ b/lib/includes/gnutls/x509.h
@@ -413,8 +413,28 @@ time_t gnutls_x509_crt_get_expiration_time(gnutls_x509_crt_t cert);
int gnutls_x509_crt_get_serial(gnutls_x509_crt_t cert,
void *result, size_t * result_size);
+typedef struct gnutls_x509_spki_st *gnutls_x509_spki_t;
+
+int gnutls_x509_spki_init(gnutls_x509_spki_t *spki);
+void gnutls_x509_spki_deinit(gnutls_x509_spki_t spki);
+int gnutls_x509_spki_get_pk_algorithm(gnutls_x509_spki_t spki);
+void gnutls_x509_spki_set_pk_algorithm(gnutls_x509_spki_t spki,
+ gnutls_pk_algorithm_t pk);
+int gnutls_x509_spki_get_digest_algorithm(gnutls_x509_spki_t spki);
+void gnutls_x509_spki_set_digest_algorithm(gnutls_x509_spki_t spki,
+ gnutls_digest_algorithm_t dig);
+int gnutls_x509_spki_get_salt_size(gnutls_x509_spki_t spki);
+void gnutls_x509_spki_set_salt_size(gnutls_x509_spki_t spki,
+ unsigned int salt_size);
+
int gnutls_x509_crt_get_pk_algorithm(gnutls_x509_crt_t cert,
unsigned int *bits);
+int gnutls_x509_crt_set_pk_algorithm(gnutls_x509_crt_t crt,
+ gnutls_x509_spki_t spki,
+ unsigned int flags);
+int gnutls_x509_crt_get_pk_algorithm2(gnutls_x509_crt_t cert,
+ gnutls_x509_spki_t spki,
+ unsigned int *bits);
int gnutls_x509_crt_get_pk_rsa_raw(gnutls_x509_crt_t crt,
gnutls_datum_t * m, gnutls_datum_t * e);
int gnutls_x509_crt_get_pk_dsa_raw(gnutls_x509_crt_t crt,
@@ -945,6 +965,7 @@ typedef enum gnutls_certificate_verify_flags {
GNUTLS_VERIFY_USE_TLS1_RSA = 1 << 13,
GNUTLS_VERIFY_IGNORE_UNKNOWN_CRIT_EXTENSIONS = 1 << 14,
GNUTLS_VERIFY_ALLOW_SIGN_WITH_SHA1 = 1 << 15,
+ GNUTLS_VERIFY_USE_RSA_PSS = 1 << 16
/* cannot exceed 2^24 due to GNUTLS_PROFILE_TO_VFLAGS() */
} gnutls_certificate_verify_flags;
@@ -1167,6 +1188,9 @@ int gnutls_x509_privkey_import_dsa_raw(gnutls_x509_privkey_t key,
int gnutls_x509_privkey_get_pk_algorithm(gnutls_x509_privkey_t key);
int gnutls_x509_privkey_get_pk_algorithm2(gnutls_x509_privkey_t
key, unsigned int *bits);
+int gnutls_x509_privkey_get_pk_algorithm3(gnutls_x509_privkey_t key,
+ gnutls_x509_spki_t spki,
+ unsigned int *bits);
int gnutls_x509_privkey_get_key_id(gnutls_x509_privkey_t key,
unsigned int flags,
unsigned char *output_data,
@@ -1391,6 +1415,12 @@ int gnutls_x509_crq_get_attribute_info(gnutls_x509_crq_t crq,
size_t * sizeof_oid);
int gnutls_x509_crq_get_pk_algorithm(gnutls_x509_crq_t crq,
unsigned int *bits);
+int gnutls_x509_crq_get_pk_algorithm2(gnutls_x509_crq_t crq,
+ gnutls_x509_spki_t spki,
+ unsigned int *bits);
+int gnutls_x509_crq_set_pk_algorithm(gnutls_x509_crq_t crq,
+ gnutls_x509_spki_t spki,
+ unsigned int flags);
int gnutls_x509_crq_get_signature_oid(gnutls_x509_crq_t crq, char *oid, size_t *oid_size);
int gnutls_x509_crq_get_pk_oid(gnutls_x509_crq_t crq, char *oid, size_t *oid_size);
diff --git a/lib/libgnutls.map b/lib/libgnutls.map
index af7a151ff4..fb6fb36620 100644
--- a/lib/libgnutls.map
+++ b/lib/libgnutls.map
@@ -1142,6 +1142,19 @@ GNUTLS_3_4
gnutls_x509_crt_set_inhibit_anypolicy;
gnutls_decode_rs_value;
gnutls_encode_rs_value;
+ gnutls_x509_spki_init;
+ gnutls_x509_spki_deinit;
+ gnutls_x509_spki_get_pk_algorithm;
+ gnutls_x509_spki_set_pk_algorithm;
+ gnutls_x509_spki_get_digest_algorithm;
+ gnutls_x509_spki_set_digest_algorithm;
+ gnutls_x509_spki_get_salt_size;
+ gnutls_x509_spki_set_salt_size;
+ gnutls_x509_crt_get_pk_algorithm2;
+ gnutls_x509_crt_set_pk_algorithm;
+ gnutls_x509_crq_get_pk_algorithm2;
+ gnutls_x509_crq_set_pk_algorithm;
+ gnutls_x509_privkey_get_pk_algorithm3;
local:
*;
};
diff --git a/lib/nettle/pk.c b/lib/nettle/pk.c
index 0bbe45f126..b635c645ff 100644
--- a/lib/nettle/pk.c
+++ b/lib/nettle/pk.c
@@ -50,6 +50,9 @@
#include <nettle/curve25519.h>
#include <gnettle.h>
#include <fips.h>
+#ifndef HAVE_NETTLE_RSA_PSS
+#include "rsa-pss.h"
+#endif
static inline const struct ecc_curve *get_supported_nist_curve(int curve);
@@ -484,13 +487,80 @@ _wrap_nettle_pk_decrypt(gnutls_pk_algorithm_t algo,
return ret;
}
+static int
+_rsa_pss_sign_digest_tr(gnutls_digest_algorithm_t dig,
+ const struct rsa_public_key *pub,
+ const struct rsa_private_key *priv,
+ void *rnd_ctx, nettle_random_func *rnd_func,
+ size_t salt_size,
+ const uint8_t *digest,
+ mpz_t s)
+{
+ int (*sign_func)(const struct rsa_public_key *,
+ const struct rsa_private_key *,
+ void *, nettle_random_func *,
+ size_t, const uint8_t *,
+ const uint8_t *,
+ mpz_t);
+ uint8_t *salt = NULL;
+ size_t hash_size;
+ int ret;
+
+ switch (dig) {
+ case GNUTLS_DIG_SHA256:
+ sign_func = rsa_pss_sha256_sign_digest_tr;
+ hash_size = 32;
+ break;
+ case GNUTLS_DIG_SHA384:
+ sign_func = rsa_pss_sha384_sign_digest_tr;
+ hash_size = 48;
+ break;
+ case GNUTLS_DIG_SHA512:
+ sign_func = rsa_pss_sha512_sign_digest_tr;
+ hash_size = 64;
+ break;
+ default:
+ gnutls_assert();
+ return GNUTLS_E_UNKNOWN_ALGORITHM;
+ }
+
+ /* This is also checked in pss_encode_mgf1, but error out earlier. */
+ if (hash_size + salt_size + 2 > pub->size)
+ return gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER);
+
+ if (salt_size > 0) {
+ salt = gnutls_malloc(salt_size);
+ if (salt == NULL)
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+
+ ret = gnutls_rnd(GNUTLS_RND_NONCE, salt, salt_size);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+ }
+
+ ret = sign_func(pub, priv, rnd_ctx, rnd_func, salt_size, salt,
+ digest, s);
+ if (ret == 0) {
+ gnutls_assert();
+ ret = GNUTLS_E_PK_SIGN_FAILED;
+ } else
+ ret = 0;
+
+ cleanup:
+ gnutls_free(salt);
+ return ret;
+}
+
/* in case of DSA puts into data, r,s
*/
static int
_wrap_nettle_pk_sign(gnutls_pk_algorithm_t algo,
gnutls_datum_t * signature,
const gnutls_datum_t * vdata,
- const gnutls_pk_params_st * pk_params)
+ const gnutls_pk_params_st * pk_params,
+ const gnutls_x509_spki_st * sign_params)
{
int ret;
unsigned int hash_len;
@@ -636,6 +706,46 @@ _wrap_nettle_pk_sign(gnutls_pk_algorithm_t algo,
break;
}
+ case GNUTLS_PK_RSA_PSS:
+ {
+ struct rsa_private_key priv;
+ struct rsa_public_key pub;
+ mpz_t s;
+
+ _rsa_params_to_privkey(pk_params, &priv);
+ ret = _rsa_params_to_pubkey(pk_params, &pub);
+ if (ret < 0)
+ return
+ gnutls_assert_val(ret);
+
+ mpz_init(s);
+
+ ret =
+ _rsa_pss_sign_digest_tr(sign_params->dig,
+ &pub, &priv,
+ NULL, rnd_nonce_func,
+ sign_params->salt_size,
+ vdata->data, s);
+ if (ret < 0) {
+ gnutls_assert();
+ ret = GNUTLS_E_PK_SIGN_FAILED;
+ goto rsa_pss_fail;
+ }
+
+ ret =
+ _gnutls_mpi_dprint_size(s, signature,
+ pub.size);
+
+ rsa_pss_fail:
+ mpz_clear(s);
+
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ break;
+ }
default:
gnutls_assert();
ret = GNUTLS_E_INTERNAL_ERROR;
@@ -651,10 +761,49 @@ _wrap_nettle_pk_sign(gnutls_pk_algorithm_t algo,
}
static int
+_rsa_pss_verify_digest(gnutls_digest_algorithm_t dig,
+ const struct rsa_public_key *pub,
+ size_t salt_size,
+ const uint8_t *digest,
+ size_t digest_size,
+ const mpz_t s)
+{
+ int (*verify_func) (const struct rsa_public_key *,
+ size_t,
+ const uint8_t *,
+ const mpz_t);
+ size_t hash_size;
+
+ switch (dig) {
+ case GNUTLS_DIG_SHA256:
+ verify_func = rsa_pss_sha256_verify_digest;
+ hash_size = 32;
+ break;
+ case GNUTLS_DIG_SHA384:
+ verify_func = rsa_pss_sha384_verify_digest;
+ hash_size = 48;
+ break;
+ case GNUTLS_DIG_SHA512:
+ verify_func = rsa_pss_sha512_verify_digest;
+ hash_size = 64;
+ break;
+ default:
+ gnutls_assert();
+ return 0;
+ }
+
+ if (digest_size != hash_size)
+ return 0;
+
+ return verify_func(pub, salt_size, digest, s);
+}
+
+static int
_wrap_nettle_pk_verify(gnutls_pk_algorithm_t algo,
const gnutls_datum_t * vdata,
const gnutls_datum_t * signature,
- const gnutls_pk_params_st * pk_params)
+ const gnutls_pk_params_st * pk_params,
+ const gnutls_x509_spki_st * sign_params)
{
int ret;
unsigned int hash_len;
@@ -776,6 +925,42 @@ _wrap_nettle_pk_verify(gnutls_pk_algorithm_t algo,
break;
}
+ case GNUTLS_PK_RSA_PSS:
+ {
+ struct rsa_public_key pub;
+
+ ret = _rsa_params_to_pubkey(pk_params, &pub);
+ if (ret < 0)
+ return
+ gnutls_assert_val(ret);
+
+ if (signature->size != pub.size)
+ return
+ gnutls_assert_val
+ (GNUTLS_E_PK_SIG_VERIFY_FAILED);
+
+ ret =
+ _gnutls_mpi_init_scan_nz(&tmp[0], signature->data,
+ signature->size);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ ret = _rsa_pss_verify_digest(sign_params->dig,
+ &pub,
+ sign_params->salt_size,
+ vdata->data, vdata->size,
+ TOMPZ(tmp[0]));
+ if (ret == 0)
+ ret =
+ gnutls_assert_val
+ (GNUTLS_E_PK_SIG_VERIFY_FAILED);
+ else
+ ret = 0;
+
+ break;
+ }
default:
gnutls_assert();
ret = GNUTLS_E_INTERNAL_ERROR;
@@ -934,6 +1119,7 @@ wrap_nettle_pk_generate_params(gnutls_pk_algorithm_t algo,
break;
}
+ case GNUTLS_PK_RSA_PSS:
case GNUTLS_PK_RSA:
case GNUTLS_PK_EC:
break;
@@ -1204,6 +1390,9 @@ static int pct_test(gnutls_pk_algorithm_t algo, const gnutls_pk_params_st* param
int ret;
gnutls_datum_t sig = {NULL, 0};
const char const_data[20] = "onetwothreefourfive";
+const char const_data_sha256[32] = "onetwothreefourfivesixseveneight";
+const char const_data_sha384[48] = "onetwothreefourfivesixseveneightnineteneleventwe";
+const char const_data_sha512[64] = "onetwothreefourfivesixseveneightnineteneleventwelvethirteenfourt";
gnutls_datum_t ddata, tmp = {NULL,0};
char* gen_data = NULL;
@@ -1216,6 +1405,24 @@ char* gen_data = NULL;
ddata.data = (void*)gen_data;
ddata.size = hash_len;
+ } else if (algo == GNUTLS_PK_RSA_PSS) {
+ switch (params->sign.dig) {
+ case GNUTLS_DIG_SHA256:
+ ddata.data = (void*)const_data_sha256;
+ ddata.size = sizeof(const_data_sha256);
+ break;
+ case GNUTLS_DIG_SHA384:
+ ddata.data = (void*)const_data_sha384;
+ ddata.size = sizeof(const_data_sha384);
+ break;
+ case GNUTLS_DIG_SHA512:
+ ddata.data = (void*)const_data_sha512;
+ ddata.size = sizeof(const_data_sha512);
+ break;
+ default:
+ ret = gnutls_assert_val(GNUTLS_E_PK_GENERATION_ERROR);
+ goto cleanup;
+ }
} else {
ddata.data = (void*)const_data;
ddata.size = sizeof(const_data);
@@ -1256,13 +1463,14 @@ char* gen_data = NULL;
*/
case GNUTLS_PK_EC: /* we only do keys for ECDSA */
case GNUTLS_PK_DSA:
- ret = _gnutls_pk_sign(algo, &sig, &ddata, params);
+ case GNUTLS_PK_RSA_PSS:
+ ret = _gnutls_pk_sign(algo, &sig, &ddata, params, &params->sign);
if (ret < 0) {
ret = gnutls_assert_val(GNUTLS_E_PK_GENERATION_ERROR);
goto cleanup;
}
- ret = _gnutls_pk_verify(algo, &ddata, &sig, params);
+ ret = _gnutls_pk_verify(algo, &ddata, &sig, params, &params->sign);
if (ret < 0) {
ret = gnutls_assert_val(GNUTLS_E_PK_GENERATION_ERROR);
gnutls_assert();
@@ -1436,6 +1644,7 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo,
break;
}
+ case GNUTLS_PK_RSA_PSS:
case GNUTLS_PK_RSA:
{
struct rsa_public_key pub;
@@ -1628,6 +1837,7 @@ wrap_nettle_pk_verify_priv_params(gnutls_pk_algorithm_t algo,
switch (algo) {
case GNUTLS_PK_RSA:
+ case GNUTLS_PK_RSA_PSS:
{
bigint_t t1 = NULL, t2 = NULL;
@@ -1833,6 +2043,7 @@ wrap_nettle_pk_verify_pub_params(gnutls_pk_algorithm_t algo,
switch (algo) {
case GNUTLS_PK_RSA:
+ case GNUTLS_PK_RSA_PSS:
case GNUTLS_PK_DSA:
return 0;
case GNUTLS_PK_EC:
diff --git a/lib/opencdk/pubkey.c b/lib/opencdk/pubkey.c
index 1c73433fd6..6e3285e65e 100644
--- a/lib/opencdk/pubkey.c
+++ b/lib/opencdk/pubkey.c
@@ -116,7 +116,7 @@ cdk_pk_verify(cdk_pubkey_t pk, cdk_pkt_signature_t sig, const byte * md)
for (i = 0; i < params.params_nr; i++)
params.params[i] = pk->mpi[i];
params.flags = 0;
- ret = _gnutls_pk_verify(algo, &di, &s_sig, &params);
+ ret = _gnutls_pk_verify(algo, &di, &s_sig, &params, &params.sign);
if (ret < 0) {
gnutls_assert();
diff --git a/lib/openpgp/privkey.c b/lib/openpgp/privkey.c
index a90541dae8..6e88a3c5fb 100644
--- a/lib/openpgp/privkey.c
+++ b/lib/openpgp/privkey.c
@@ -1353,7 +1353,7 @@ gnutls_openpgp_privkey_sign_hash(gnutls_openpgp_privkey_t key,
}
- result = _gnutls_pk_sign(pk_algorithm, signature, hash, &params);
+ result = _gnutls_pk_sign(pk_algorithm, signature, hash, &params, &params.sign);
gnutls_pk_params_clear(&params);
gnutls_pk_params_release(&params);
diff --git a/lib/pk.c b/lib/pk.c
index c2c62886f7..0e6443a74d 100644
--- a/lib/pk.c
+++ b/lib/pk.c
@@ -332,6 +332,8 @@ int _gnutls_pk_params_copy(gnutls_pk_params_st * dst,
}
dst->palgo = src->palgo;
+ memcpy(&dst->sign, &src->sign, sizeof(gnutls_x509_spki_st));
+
return 0;
fail:
@@ -374,6 +376,24 @@ void gnutls_pk_params_clear(gnutls_pk_params_st * p)
}
}
+unsigned
+_gnutls_find_rsa_pss_salt_size(unsigned bits, const mac_entry_st *me,
+ unsigned salt_size)
+{
+ unsigned max_salt_size, digest_size;
+
+ digest_size = _gnutls_hash_get_algo_len(me);
+ max_salt_size = (bits + 7) / 8 - digest_size - 2;
+
+ if (salt_size < digest_size)
+ salt_size = digest_size;
+
+ if (salt_size > max_salt_size)
+ salt_size = max_salt_size;
+
+ return salt_size;
+}
+
/* Writes the digest information and the digest in a DER encoded
* structure. The digest info is allocated and stored into the info structure.
*/
@@ -596,7 +616,7 @@ _gnutls_params_get_rsa_raw(const gnutls_pk_params_st* params,
return GNUTLS_E_INVALID_REQUEST;
}
- if (params->algo != GNUTLS_PK_RSA) {
+ if (!GNUTLS_PK_IS_RSA(params->algo)) {
gnutls_assert();
return GNUTLS_E_INVALID_REQUEST;
}
@@ -890,6 +910,7 @@ pk_prepare_hash(gnutls_pk_algorithm_t pk,
_gnutls_free_datum(&old_digest);
break;
+ case GNUTLS_PK_RSA_PSS:
case GNUTLS_PK_DSA:
case GNUTLS_PK_EC:
break;
diff --git a/lib/pk.h b/lib/pk.h
index c4a25bcd7c..49c8b240d8 100644
--- a/lib/pk.h
+++ b/lib/pk.h
@@ -28,8 +28,8 @@ extern gnutls_crypto_pk_st _gnutls_pk_ops;
#define _gnutls_pk_encrypt( algo, ciphertext, plaintext, params) _gnutls_pk_ops.encrypt( algo, ciphertext, plaintext, params)
#define _gnutls_pk_decrypt( algo, ciphertext, plaintext, params) _gnutls_pk_ops.decrypt( algo, ciphertext, plaintext, params)
-#define _gnutls_pk_sign( algo, sig, data, params) _gnutls_pk_ops.sign( algo, sig, data, params)
-#define _gnutls_pk_verify( algo, data, sig, params) _gnutls_pk_ops.verify( algo, data, sig, params)
+#define _gnutls_pk_sign( algo, sig, data, params, sign_params) _gnutls_pk_ops.sign( algo, sig, data, params, sign_params)
+#define _gnutls_pk_verify( algo, data, sig, params, sign_params) _gnutls_pk_ops.verify( algo, data, sig, params, sign_params)
#define _gnutls_pk_verify_priv_params( algo, params) _gnutls_pk_ops.verify_priv_params( algo, params)
#define _gnutls_pk_verify_pub_params( algo, params) _gnutls_pk_ops.verify_pub_params( algo, params)
#define _gnutls_pk_derive( algo, out, pub, priv) _gnutls_pk_ops.derive( algo, out, pub, priv)
@@ -101,4 +101,7 @@ int pk_hash_data(gnutls_pk_algorithm_t pk, const mac_entry_st * hash,
gnutls_pk_params_st * params, const gnutls_datum_t * data,
gnutls_datum_t * digest);
+unsigned _gnutls_find_rsa_pss_salt_size(unsigned bits, const mac_entry_st *me,
+ unsigned salt_size);
+
#endif /* GNUTLS_PK_H */
diff --git a/lib/privkey.c b/lib/privkey.c
index 1b4eb48208..1bfca03a8d 100644
--- a/lib/privkey.c
+++ b/lib/privkey.c
@@ -40,9 +40,9 @@
static int
_gnutls_privkey_sign_raw_data(gnutls_privkey_t key,
- unsigned flags,
const gnutls_datum_t * data,
- gnutls_datum_t * signature);
+ gnutls_datum_t * signature,
+ gnutls_x509_spki_st * params);
/**
* gnutls_privkey_get_type:
@@ -158,8 +158,10 @@ privkey_to_pubkey(gnutls_pk_algorithm_t pk,
pub->algo = priv->algo;
pub->flags = priv->flags;
+ memcpy(&pub->sign, &priv->sign, sizeof(gnutls_x509_spki_st));
switch (pk) {
+ case GNUTLS_PK_RSA_PSS:
case GNUTLS_PK_RSA:
pub->params[0] = _gnutls_mpi_copy(priv->params[0]);
pub->params[1] = _gnutls_mpi_copy(priv->params[1]);
@@ -296,6 +298,69 @@ _gnutls_privkey_get_public_mpis(gnutls_privkey_t key,
return ret;
}
+/* This function retrieves default sign parameters from KEY. */
+int
+_gnutls_privkey_get_sign_params(gnutls_privkey_t key,
+ gnutls_x509_spki_st * params)
+{
+ switch (key->type) {
+#ifdef ENABLE_OPENPGP
+ case GNUTLS_PRIVKEY_OPENPGP:
+ break;
+#endif
+#ifdef ENABLE_PKCS11
+ case GNUTLS_PRIVKEY_PKCS11:
+ break;
+#endif
+ case GNUTLS_PRIVKEY_X509:
+ return _gnutls_x509_privkey_get_sign_params(key->key.x509,
+ params);
+ default:
+ gnutls_assert();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ memset(params, 0, sizeof(gnutls_x509_spki_st));
+
+ return 0;
+}
+
+/* This function fills in PARAMS with the necessary parameters to sign
+ * with PK and DIG. PARAMS must be initialized with
+ * _gnutls_privkey_get_sign_params in advance. */
+int
+_gnutls_privkey_find_sign_params(gnutls_privkey_t key,
+ gnutls_pk_algorithm_t pk,
+ gnutls_digest_algorithm_t dig,
+ unsigned flags,
+ gnutls_x509_spki_st *params)
+{
+ switch (key->type) {
+#ifdef ENABLE_OPENPGP
+ case GNUTLS_PRIVKEY_OPENPGP:
+ break;
+#endif
+#ifdef ENABLE_PKCS11
+ case GNUTLS_PRIVKEY_PKCS11:
+ break;
+#endif
+ case GNUTLS_PRIVKEY_X509:
+ return _gnutls_x509_privkey_find_sign_params(key->key.x509,
+ pk,
+ dig,
+ flags,
+ params);
+ default:
+ gnutls_assert();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ params->pk = pk;
+ params->dig = dig;
+
+ return 0;
+}
+
/**
* gnutls_privkey_init:
* @key: A pointer to the type to be initialized
@@ -1084,25 +1149,53 @@ gnutls_privkey_sign_data(gnutls_privkey_t signer,
gnutls_datum_t * signature)
{
int ret;
- gnutls_datum_t digest;
- const mac_entry_st *me = hash_to_entry(hash);
+ gnutls_x509_spki_st params;
if (flags & GNUTLS_PRIVKEY_SIGN_FLAG_TLS1_RSA)
return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
- ret = pk_hash_data(signer->pk_algorithm, me, NULL, data, &digest);
+ ret = _gnutls_privkey_get_sign_params(signer, &params);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ ret = _gnutls_privkey_find_sign_params(signer, signer->pk_algorithm,
+ hash, flags, &params);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ return privkey_sign_data(signer, data, signature, &params);
+}
+
+int
+privkey_sign_data(gnutls_privkey_t signer,
+ const gnutls_datum_t * data,
+ gnutls_datum_t * signature,
+ gnutls_x509_spki_st * params)
+{
+ int ret;
+ gnutls_datum_t digest;
+ const mac_entry_st *me = hash_to_entry(params->dig);
+
+ if (me == NULL)
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+ ret = pk_hash_data(params->pk, me, NULL, data, &digest);
if (ret < 0) {
gnutls_assert();
return ret;
}
- ret = pk_prepare_hash(signer->pk_algorithm, me, &digest);
+ ret = pk_prepare_hash(params->pk, me, &digest);
if (ret < 0) {
gnutls_assert();
goto cleanup;
}
- ret = _gnutls_privkey_sign_raw_data(signer, flags, &digest, signature);
+ ret = _gnutls_privkey_sign_raw_data(signer, &digest, signature, params);
_gnutls_free_datum(&digest);
if (ret < 0) {
@@ -1149,11 +1242,37 @@ gnutls_privkey_sign_hash(gnutls_privkey_t signer,
gnutls_datum_t * signature)
{
int ret;
- gnutls_datum_t digest;
+ gnutls_x509_spki_st params;
+
+ ret = _gnutls_privkey_get_sign_params(signer, &params);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ ret = _gnutls_privkey_find_sign_params(signer, signer->pk_algorithm,
+ hash_algo, 0, &params);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
if (flags & GNUTLS_PRIVKEY_SIGN_FLAG_TLS1_RSA)
- return _gnutls_privkey_sign_raw_data(signer, flags,
- hash_data, signature);
+ return _gnutls_privkey_sign_raw_data(signer,
+ hash_data, signature,
+ &params);
+
+ return privkey_sign_hash(signer, hash_data, signature, &params);
+}
+
+int
+privkey_sign_hash(gnutls_privkey_t signer,
+ const gnutls_datum_t * hash_data,
+ gnutls_datum_t * signature,
+ gnutls_x509_spki_st * params)
+{
+ int ret;
+ gnutls_datum_t digest;
digest.data = gnutls_malloc(hash_data->size);
if (digest.data == NULL) {
@@ -1163,15 +1282,15 @@ gnutls_privkey_sign_hash(gnutls_privkey_t signer,
digest.size = hash_data->size;
memcpy(digest.data, hash_data->data, digest.size);
- ret =
- pk_prepare_hash(signer->pk_algorithm, hash_to_entry(hash_algo),
- &digest);
+ ret = pk_prepare_hash(params->pk, hash_to_entry(params->dig), &digest);
if (ret < 0) {
gnutls_assert();
goto cleanup;
}
- ret = _gnutls_privkey_sign_raw_data(signer, flags, &digest, signature);
+ ret = _gnutls_privkey_sign_raw_data(signer,
+ &digest, signature,
+ params);
if (ret < 0) {
gnutls_assert();
goto cleanup;
@@ -1187,9 +1306,9 @@ gnutls_privkey_sign_hash(gnutls_privkey_t signer,
/*-
* gnutls_privkey_sign_raw_data:
* @key: Holds the key
- * @flags: should be zero
* @data: holds the data to be signed
* @signature: will contain the signature allocated with gnutls_malloc()
+ * @params: holds the signing parameters
*
* This function will sign the given data using a signature algorithm
* supported by the private key. Note that this is a low-level function
@@ -1207,9 +1326,9 @@ gnutls_privkey_sign_hash(gnutls_privkey_t signer,
-*/
static int
_gnutls_privkey_sign_raw_data(gnutls_privkey_t key,
- unsigned flags,
const gnutls_datum_t * data,
- gnutls_datum_t * signature)
+ gnutls_datum_t * signature,
+ gnutls_x509_spki_st * params)
{
switch (key->type) {
#ifdef ENABLE_OPENPGP
@@ -1223,8 +1342,8 @@ _gnutls_privkey_sign_raw_data(gnutls_privkey_t key,
data, signature);
#endif
case GNUTLS_PRIVKEY_X509:
- return _gnutls_pk_sign(key->key.x509->pk_algorithm,
- signature, data, &key->key.x509->params);
+ return _gnutls_pk_sign(params->pk, signature, data,
+ &key->key.x509->params, params);
case GNUTLS_PRIVKEY_EXT:
if (key->key.ext.sign_func == NULL)
return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
diff --git a/lib/pubkey.c b/lib/pubkey.c
index 7c42f67805..e4cb1c92f1 100644
--- a/lib/pubkey.c
+++ b/lib/pubkey.c
@@ -43,6 +43,7 @@ unsigned pubkey_to_bits(gnutls_pk_algorithm_t pk, gnutls_pk_params_st * params)
{
switch (pk) {
case GNUTLS_PK_RSA:
+ case GNUTLS_PK_RSA_PSS:
return _gnutls_mpi_get_nbits(params->params[RSA_MODULUS]);
case GNUTLS_PK_DSA:
return _gnutls_mpi_get_nbits(params->params[DSA_P]);
@@ -294,6 +295,7 @@ gnutls_pubkey_get_preferred_hash_algorithm(gnutls_pubkey_t key,
ret = 0;
break;
case GNUTLS_PK_RSA:
+ case GNUTLS_PK_RSA_PSS:
if (hash)
*hash = GNUTLS_DIG_SHA256;
ret = 0;
@@ -371,6 +373,7 @@ gnutls_pubkey_import_pkcs11(gnutls_pubkey_t key,
switch (obj->pk_algorithm) {
case GNUTLS_PK_RSA:
+ case GNUTLS_PK_RSA_PSS:
ret = gnutls_pubkey_import_rsa_raw(key, &obj->pubkey[0],
&obj->pubkey[1]);
break;
@@ -838,7 +841,7 @@ gnutls_pubkey_export_rsa_raw(gnutls_pubkey_t key,
return GNUTLS_E_INVALID_REQUEST;
}
- if (key->pk_algorithm != GNUTLS_PK_RSA) {
+ if (!GNUTLS_PK_IS_RSA(key->pk_algorithm)) {
gnutls_assert();
return GNUTLS_E_INVALID_REQUEST;
}
@@ -1611,6 +1614,7 @@ gnutls_pubkey_verify_data2(gnutls_pubkey_t pubkey,
{
int ret;
const mac_entry_st *me;
+ gnutls_x509_spki_st params;
if (pubkey == NULL) {
gnutls_assert();
@@ -1620,12 +1624,32 @@ gnutls_pubkey_verify_data2(gnutls_pubkey_t pubkey,
if (flags & OLD_PUBKEY_VERIFY_FLAG_TLS1_RSA || flags & GNUTLS_VERIFY_USE_TLS1_RSA)
return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
- me = hash_to_entry(gnutls_sign_get_hash_algorithm(algo));
+ memcpy(&params, &pubkey->params.sign, sizeof(gnutls_x509_spki_st));
+
+ params.pk = pubkey->pk_algorithm;
+ params.dig = gnutls_sign_get_hash_algorithm(algo);
+ me = hash_to_entry(params.dig);
if (me == NULL)
return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
- ret = pubkey_verify_data(pubkey->pk_algorithm, me,
- data, signature, &pubkey->params);
+ if (flags & GNUTLS_VERIFY_USE_RSA_PSS) {
+ unsigned bits;
+
+ if (!GNUTLS_PK_IS_RSA(pubkey->pk_algorithm))
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+ /* The requested sign algorithm is RSA-PSS, while the
+ * pubkey doesn't include parameter information. Fill
+ * it with the same way as gnutls_privkey_sign*. */
+ if (pubkey->pk_algorithm == GNUTLS_PK_RSA) {
+ gnutls_pubkey_get_pk_algorithm(pubkey, &bits);
+ params.salt_size = _gnutls_find_rsa_pss_salt_size(bits, me, 0);
+ }
+ params.pk = GNUTLS_PK_RSA_PSS;
+ }
+
+ ret = pubkey_verify_data(params.pk, me, data, signature, &pubkey->params,
+ &params);
if (ret < 0) {
gnutls_assert();
return ret;
@@ -1664,20 +1688,54 @@ gnutls_pubkey_verify_hash2(gnutls_pubkey_t key,
const gnutls_datum_t * signature)
{
const mac_entry_st *me;
+ gnutls_x509_spki_st params;
if (key == NULL) {
gnutls_assert();
return GNUTLS_E_INVALID_REQUEST;
}
+ memcpy(&params, &key->params.sign, sizeof(gnutls_x509_spki_st));
+
if (flags & OLD_PUBKEY_VERIFY_FLAG_TLS1_RSA || flags & GNUTLS_VERIFY_USE_TLS1_RSA) {
- return _gnutls_pk_verify(GNUTLS_PK_RSA, hash, signature,
- &key->params);
+ params.pk = GNUTLS_PK_RSA;
+ return _gnutls_pk_verify(params.pk, hash, signature,
+ &key->params, &params);
} else {
- me = hash_to_entry(gnutls_sign_get_hash_algorithm(algo));
- return pubkey_verify_hashed_data(key->pk_algorithm, me,
+ params.pk = key->pk_algorithm;
+ params.dig = gnutls_sign_get_hash_algorithm(algo);
+ /* This can be NULL here, if pubkey is DSA. For RSA it
+ * is checked below. */
+ me = hash_to_entry(params.dig);
+
+ if (flags & GNUTLS_VERIFY_USE_RSA_PSS) {
+ int ret;
+ gnutls_pk_algorithm_t pk;
+ unsigned bits;
+
+ ret = gnutls_pubkey_get_pk_algorithm(key, &bits);
+ if (ret < 0) {
+ gnutls_assert();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ pk = ret;
+
+ /* The requested sign algorithm is RSA-PSS, while the
+ * pubkey doesn't include parameter information */
+ if (pk == GNUTLS_PK_RSA) {
+ if (me == NULL)
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+ params.salt_size =
+ _gnutls_find_rsa_pss_salt_size(bits, me, 0);
+ }
+ params.pk = GNUTLS_PK_RSA_PSS;
+ }
+
+ return pubkey_verify_hashed_data(params.pk, me,
hash, signature,
- &key->params);
+ &key->params,
+ &params);
}
}
@@ -1785,7 +1843,8 @@ _pkcs1_rsa_verify_sig(const mac_entry_st * me,
const gnutls_datum_t * text,
const gnutls_datum_t * prehash,
const gnutls_datum_t * signature,
- gnutls_pk_params_st * params)
+ gnutls_pk_params_st * params,
+ gnutls_x509_spki_st * sign_params)
{
int ret;
uint8_t md[MAX_HASH_SIZE], *cmp;
@@ -1823,7 +1882,8 @@ _pkcs1_rsa_verify_sig(const mac_entry_st * me,
if (ret < 0)
return gnutls_assert_val(ret);
- ret = _gnutls_pk_verify(GNUTLS_PK_RSA, &di, signature, params);
+ ret = _gnutls_pk_verify(GNUTLS_PK_RSA, &di, signature, params,
+ sign_params);
_gnutls_free_datum(&di);
return ret;
@@ -1836,7 +1896,8 @@ dsa_verify_hashed_data(gnutls_pk_algorithm_t pk,
const mac_entry_st * algo,
const gnutls_datum_t * hash,
const gnutls_datum_t * signature,
- gnutls_pk_params_st * params)
+ gnutls_pk_params_st * params,
+ gnutls_x509_spki_st * sign_params)
{
gnutls_datum_t digest;
unsigned int hash_len;
@@ -1863,7 +1924,7 @@ dsa_verify_hashed_data(gnutls_pk_algorithm_t pk,
digest.data = hash->data;
digest.size = hash->size;
- return _gnutls_pk_verify(pk, &digest, signature, params);
+ return _gnutls_pk_verify(pk, &digest, signature, params, sign_params);
}
static int
@@ -1871,7 +1932,8 @@ dsa_verify_data(gnutls_pk_algorithm_t pk,
const mac_entry_st * algo,
const gnutls_datum_t * data,
const gnutls_datum_t * signature,
- gnutls_pk_params_st * params)
+ gnutls_pk_params_st * params,
+ gnutls_x509_spki_st * sign_params)
{
int ret;
uint8_t _digest[MAX_HASH_SIZE];
@@ -1888,7 +1950,7 @@ dsa_verify_data(gnutls_pk_algorithm_t pk,
digest.data = _digest;
digest.size = _gnutls_hash_get_algo_len(algo);
- return _gnutls_pk_verify(pk, &digest, signature, params);
+ return _gnutls_pk_verify(pk, &digest, signature, params, sign_params);
}
/* Verifies the signature data, and returns GNUTLS_E_PK_SIG_VERIFY_FAILED if
@@ -1896,17 +1958,16 @@ dsa_verify_data(gnutls_pk_algorithm_t pk,
*/
int
pubkey_verify_hashed_data(gnutls_pk_algorithm_t pk,
- const mac_entry_st * hash_algo,
+ const mac_entry_st *hash_algo,
const gnutls_datum_t * hash,
const gnutls_datum_t * signature,
- gnutls_pk_params_st * issuer_params)
+ gnutls_pk_params_st * params,
+ gnutls_x509_spki_st * sign_params)
{
-
switch (pk) {
case GNUTLS_PK_RSA:
-
if (_pkcs1_rsa_verify_sig
- (hash_algo, NULL, hash, signature, issuer_params) != 0)
+ (hash_algo, NULL, hash, signature, params, sign_params) != 0)
{
gnutls_assert();
return GNUTLS_E_PK_SIG_VERIFY_FAILED;
@@ -1915,10 +1976,11 @@ pubkey_verify_hashed_data(gnutls_pk_algorithm_t pk,
return 1;
break;
+ case GNUTLS_PK_RSA_PSS:
case GNUTLS_PK_EC:
case GNUTLS_PK_DSA:
if (dsa_verify_hashed_data
- (pk, hash_algo, hash, signature, issuer_params) != 0) {
+ (pk, hash_algo, hash, signature, params, sign_params) != 0) {
gnutls_assert();
return GNUTLS_E_PK_SIG_VERIFY_FAILED;
}
@@ -1940,14 +2002,13 @@ pubkey_verify_data(gnutls_pk_algorithm_t pk,
const mac_entry_st * me,
const gnutls_datum_t * data,
const gnutls_datum_t * signature,
- gnutls_pk_params_st * issuer_params)
+ gnutls_pk_params_st * params,
+ gnutls_x509_spki_st * sign_params)
{
-
switch (pk) {
case GNUTLS_PK_RSA:
-
if (_pkcs1_rsa_verify_sig
- (me, data, NULL, signature, issuer_params) != 0) {
+ (me, data, NULL, signature, params, sign_params) != 0) {
gnutls_assert();
return GNUTLS_E_PK_SIG_VERIFY_FAILED;
}
@@ -1955,10 +2016,11 @@ pubkey_verify_data(gnutls_pk_algorithm_t pk,
return 1;
break;
+ case GNUTLS_PK_RSA_PSS:
case GNUTLS_PK_EC:
case GNUTLS_PK_DSA:
- if (dsa_verify_data(pk, me, data, signature, issuer_params)
- != 0) {
+ if (dsa_verify_data
+ (pk, me, data, signature, params, sign_params) != 0) {
gnutls_assert();
return GNUTLS_E_PK_SIG_VERIFY_FAILED;
}
diff --git a/lib/x509/Makefile.am b/lib/x509/Makefile.am
index f4d9463c55..46d567ed95 100644
--- a/lib/x509/Makefile.am
+++ b/lib/x509/Makefile.am
@@ -71,6 +71,7 @@ libgnutls_x509_la_SOURCES = \
pkcs7-output.c \
virt-san.c \
virt-san.h \
+ spki.c \
x509_ext_int.h \
tls_features.c \
krb5.c krb5.h \
diff --git a/lib/x509/common.c b/lib/x509/common.c
index 38425bde4c..a07b0ec5ed 100644
--- a/lib/x509/common.c
+++ b/lib/x509/common.c
@@ -1240,19 +1240,48 @@ int
_gnutls_x509_get_signature_algorithm(ASN1_TYPE src, const char *src_name)
{
int result;
+ char name[128];
gnutls_datum_t sa = {NULL, 0};
- /* Read the signature algorithm. Note that parameters are not
- * read. They will be read from the issuer's certificate if needed.
- */
- result = _gnutls_x509_read_value(src, src_name, &sa);
+ _gnutls_str_cpy(name, sizeof(name), src_name);
+ _gnutls_str_cat(name, sizeof(name), ".algorithm");
+
+ /* Read the signature algorithm */
+ result = _gnutls_x509_read_value(src, name, &sa);
if (result < 0) {
gnutls_assert();
return result;
}
- result = gnutls_oid_to_sign((char *) sa.data);
+ /* Read the signature parameters. Unless the algorithm is
+ * RSA-PSS, parameters are not read. They will be read from
+ * the issuer's certificate if needed.
+ */
+ if (sa.data && strcmp ((char *) sa.data, PK_PKIX1_RSA_PSS_OID) == 0) {
+ gnutls_datum_t der = {NULL, 0};
+ gnutls_x509_spki_st params;
+
+ _gnutls_str_cpy(name, sizeof(name), src_name);
+ _gnutls_str_cat(name, sizeof(name), ".parameters");
+
+ result = _gnutls_x509_read_value(src, name, &der);
+ if (result < 0) {
+ _gnutls_free_datum(&sa);
+ return gnutls_assert_val(result);
+ }
+
+ result = _gnutls_x509_read_rsa_pss_params(der.data, der.size,
+ &params);
+ _gnutls_free_datum(&der);
+
+ if (result == 0)
+ result = gnutls_pk_to_sign(params.pk, params.dig);
+ else if (result == GNUTLS_E_UNKNOWN_ALGORITHM)
+ result = GNUTLS_SIGN_UNKNOWN;
+ } else {
+ result = gnutls_oid_to_sign((char *) sa.data);
+ }
_gnutls_free_datum(&sa);
diff --git a/lib/x509/common.h b/lib/x509/common.h
index b0c1c5e29f..0cca5272b8 100644
--- a/lib/x509/common.h
+++ b/lib/x509/common.h
@@ -46,6 +46,7 @@
/* public key algorithm's OIDs
*/
#define PK_PKIX1_RSA_OID "1.2.840.113549.1.1.1"
+#define PK_PKIX1_RSA_PSS_OID "1.2.840.113549.1.1.10"
#define PK_X509_RSA_OID "2.5.8.1.1"
#define PK_DSA_OID "1.2.840.10040.4.1"
#define PK_GOST_R3410_94_OID "1.2.643.2.2.20"
@@ -89,6 +90,7 @@
#define XMPP_OID "1.3.6.1.5.5.7.8.5"
#define KRB5_PRINCIPAL_OID "1.3.6.1.5.2.2"
+#define PKIX1_RSA_PSS_MGF1_OID "1.2.840.113549.1.1.8"
#define ASN1_NULL "\x05\x00"
#define ASN1_NULL_SIZE 2
diff --git a/lib/x509/crl.c b/lib/x509/crl.c
index bd307ca42a..928f6c05c9 100644
--- a/lib/x509/crl.c
+++ b/lib/x509/crl.c
@@ -373,32 +373,13 @@ gnutls_x509_crl_get_issuer_dn3(gnutls_x509_crl_t crl, gnutls_datum_t * dn, unsig
**/
int gnutls_x509_crl_get_signature_algorithm(gnutls_x509_crl_t crl)
{
- int result;
- gnutls_datum_t sa;
-
if (crl == NULL) {
gnutls_assert();
return GNUTLS_E_INVALID_REQUEST;
}
- /* Read the signature algorithm. Note that parameters are not
- * read. They will be read from the issuer's certificate if needed.
- */
-
- result =
- _gnutls_x509_read_value(crl->crl,
- "signatureAlgorithm.algorithm", &sa);
-
- if (result < 0) {
- gnutls_assert();
- return result;
- }
-
- result = gnutls_oid_to_sign((const char *) sa.data);
-
- _gnutls_free_datum(&sa);
-
- return result;
+ return _gnutls_x509_get_signature_algorithm(crl->crl,
+ "signatureAlgorithm");
}
/**
diff --git a/lib/x509/crl_write.c b/lib/x509/crl_write.c
index 6e5cfc9f28..a5930a45f9 100644
--- a/lib/x509/crl_write.c
+++ b/lib/x509/crl_write.c
@@ -499,7 +499,7 @@ gnutls_x509_crl_privkey_sign(gnutls_x509_crl_t crl,
disable_optional_stuff(crl);
result = _gnutls_x509_pkix_sign(crl->crl, "tbsCertList",
- dig, issuer, issuer_key);
+ dig, 0, issuer, issuer_key);
if (result < 0) {
gnutls_assert();
return result;
diff --git a/lib/x509/crq.c b/lib/x509/crq.c
index 13978baa40..e6f774d1f7 100644
--- a/lib/x509/crq.c
+++ b/lib/x509/crq.c
@@ -36,6 +36,7 @@
#include <gnutls/x509-ext.h>
#include "x509_int.h"
#include <libtasn1.h>
+#include <pk.h>
/**
* gnutls_x509_crq_init:
@@ -175,7 +176,7 @@ gnutls_x509_crq_import(gnutls_x509_crq_t crq,
int gnutls_x509_crq_get_signature_algorithm(gnutls_x509_crq_t crq)
{
return _gnutls_x509_get_signature_algorithm(crq->crq,
- "signatureAlgorithm.algorithm");
+ "signatureAlgorithm");
}
/**
@@ -1278,6 +1279,33 @@ gnutls_x509_crq_export2(gnutls_x509_crq_t crq,
int
gnutls_x509_crq_get_pk_algorithm(gnutls_x509_crq_t crq, unsigned int *bits)
{
+ return gnutls_x509_crq_get_pk_algorithm2(crq, NULL, bits);
+}
+
+/**
+ * gnutls_x509_crq_get_pk_algorithm2:
+ * @crq: should contain a #gnutls_x509_crq_t type
+ * @spki: a SubjectPublicKeyInfo structure of type #gnutls_x509_spki_t
+ * @bits: if bits is non-%NULL it will hold the size of the parameters' in bits
+ *
+ * This function will return the public key algorithm of a PKCS#10
+ * certificate request.
+ *
+ * If @spki is non null, it should have enough size to hold the
+ * parameters.
+ *
+ * If @bits is non-%NULL, it should have enough size to hold the
+ * parameters size in bits. For RSA the bits returned is the modulus.
+ * For DSA the bits returned are of the public exponent.
+ *
+ * Returns: a member of the #gnutls_pk_algorithm_t enumeration on
+ * success, or a negative error code on error.
+ **/
+int
+gnutls_x509_crq_get_pk_algorithm2(gnutls_x509_crq_t crq,
+ gnutls_x509_spki_t spki,
+ unsigned int *bits)
+{
int result;
if (crq == NULL) {
@@ -1289,6 +1317,24 @@ gnutls_x509_crq_get_pk_algorithm(gnutls_x509_crq_t crq, unsigned int *bits)
(crq->crq, "certificationRequestInfo.subjectPKInfo", bits);
if (result < 0) {
gnutls_assert();
+ return result;
+ }
+
+ if (spki) {
+ gnutls_x509_spki_st params;
+
+ spki->pk = result;
+
+ result = _gnutls_x509_crq_read_sign_params(crq, &params);
+ if (result < 0) {
+ gnutls_assert();
+ return result;
+ }
+
+ spki->dig = params.dig;
+ spki->salt_size = params.salt_size;
+
+ return spki->pk;
}
return result;
@@ -2774,6 +2820,8 @@ gnutls_x509_crq_privkey_sign(gnutls_x509_crq_t crq, gnutls_privkey_t key,
int result;
gnutls_datum_t signature;
gnutls_datum_t tbs;
+ gnutls_pk_algorithm_t pk;
+ gnutls_x509_spki_st params;
if (crq == NULL) {
gnutls_assert();
@@ -2790,6 +2838,19 @@ gnutls_x509_crq_privkey_sign(gnutls_x509_crq_t crq, gnutls_privkey_t key,
}
}
+ result = _gnutls_privkey_get_sign_params(key, &params);
+ if (result < 0) {
+ gnutls_assert();
+ return result;
+ }
+
+ pk = gnutls_privkey_get_pk_algorithm(key, NULL);
+ result = _gnutls_privkey_find_sign_params(key, pk, dig, 0, &params);
+ if (result < 0) {
+ gnutls_assert();
+ return result;
+ }
+
/* Step 1. Self sign the request.
*/
result =
@@ -2801,7 +2862,7 @@ gnutls_x509_crq_privkey_sign(gnutls_x509_crq_t crq, gnutls_privkey_t key,
return result;
}
- result = gnutls_privkey_sign_data(key, dig, 0, &tbs, &signature);
+ result = privkey_sign_data(key, &tbs, &signature, &params);
gnutls_free(tbs.data);
if (result < 0) {
@@ -2825,9 +2886,8 @@ gnutls_x509_crq_privkey_sign(gnutls_x509_crq_t crq, gnutls_privkey_t key,
/* Step 3. Write the signatureAlgorithm field.
*/
result =
- _gnutls_x509_write_sig_params(crq->crq, "signatureAlgorithm",
- gnutls_privkey_get_pk_algorithm
- (key, NULL), dig, 0);
+ _gnutls_x509_write_sign_params(crq->crq, "signatureAlgorithm",
+ &params);
if (result < 0) {
gnutls_assert();
return result;
@@ -2856,6 +2916,7 @@ int gnutls_x509_crq_verify(gnutls_x509_crq_t crq, unsigned int flags)
gnutls_datum_t signature = { NULL, 0 };
gnutls_pk_params_st params;
gnutls_digest_algorithm_t algo;
+ gnutls_x509_spki_st sign_params;
int ret;
gnutls_pk_params_init(&params);
@@ -2871,7 +2932,7 @@ int gnutls_x509_crq_verify(gnutls_x509_crq_t crq, unsigned int flags)
ret =
_gnutls_x509_get_signature_algorithm(crq->crq,
- "signatureAlgorithm.algorithm");
+ "signatureAlgorithm");
if (ret < 0) {
gnutls_assert();
goto cleanup;
@@ -2892,10 +2953,18 @@ int gnutls_x509_crq_verify(gnutls_x509_crq_t crq, unsigned int flags)
goto cleanup;
}
+ ret = _gnutls_x509_read_sign_params(crq->crq,
+ "signatureAlgorithm",
+ &sign_params);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
ret =
- pubkey_verify_data(gnutls_x509_crq_get_pk_algorithm(crq, NULL),
+ pubkey_verify_data(sign_params.pk,
hash_to_entry(algo), &data, &signature,
- &params);
+ &params, &sign_params);
if (ret < 0) {
gnutls_assert();
goto cleanup;
@@ -3120,3 +3189,102 @@ gnutls_x509_crq_set_extension_by_oid(gnutls_x509_crq_t crq,
return 0;
}
+
+/**
+ * gnutls_x509_crq_set_pk_algorithm:
+ * @crq: a certificate request of type #gnutls_x509_crq_t
+ * @spki: a SubjectPublicKeyInfo structure of type #gnutls_x509_spki_t
+ * @flags: must be zero
+ *
+ * This function will set the certificate request's subject public key
+ * information explicitly. This is intended to be used in the cases
+ * where a single public key (e.g., RSA) can be used for multiple
+ * signature algorithms (RSA PKCS1-1.5, and RSA-PSS).
+ *
+ * To export the public key (i.e., the SubjectPublicKeyInfo part), check
+ * gnutls_pubkey_import_x509().
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
+ * negative error value.
+ *
+ * Since: 3.6.0
+ **/
+int
+gnutls_x509_crq_set_pk_algorithm(gnutls_x509_crq_t crq,
+ gnutls_x509_spki_t spki,
+ unsigned int flags)
+{
+ int result;
+ gnutls_pk_algorithm_t crq_pk;
+ gnutls_x509_spki_st params;
+ unsigned bits;
+
+ if (crq == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ result = gnutls_x509_crq_get_pk_algorithm(crq, &bits);
+ if (result < 0) {
+ gnutls_assert();
+ return result;
+ }
+
+ crq_pk = result;
+
+ if (spki->pk != GNUTLS_PK_RSA_PSS) {
+ if (crq_pk == spki->pk)
+ return 0;
+
+ gnutls_assert();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ if (crq_pk == GNUTLS_PK_RSA) {
+ const mac_entry_st *me;
+
+ me = hash_to_entry(spki->dig);
+ if (unlikely(me == NULL)) {
+ gnutls_assert();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ memset(&params, 0, sizeof(gnutls_x509_spki_st));
+ params.pk = spki->pk;
+ params.dig = spki->dig;
+
+ /* If salt size is zero, find the optimal salt size. */
+ if (spki->salt_size == 0) {
+ params.salt_size =
+ _gnutls_find_rsa_pss_salt_size(bits, me,
+ spki->salt_size);
+ } else
+ params.salt_size = spki->salt_size;
+ } else if (crq_pk == GNUTLS_PK_RSA_PSS) {
+ result = _gnutls_x509_crq_read_sign_params(crq, &params);
+ if (result < 0) {
+ gnutls_assert();
+ return result;
+ }
+
+ if (params.dig != spki->dig ||
+ params.salt_size > spki->salt_size) {
+ gnutls_assert();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ params.salt_size = spki->salt_size;
+ }
+
+ result = _gnutls_x509_write_sign_params(crq->crq,
+ "certificationRequestInfo."
+ "subjectPKInfo."
+ "algorithm",
+ &params);
+ if (result < 0) {
+ gnutls_assert();
+ return result;
+ }
+
+ return 0;
+}
diff --git a/lib/x509/key_decode.c b/lib/x509/key_decode.c
index 1e5cc43c3a..8d929f7315 100644
--- a/lib/x509/key_decode.c
+++ b/lib/x509/key_decode.c
@@ -234,6 +234,144 @@ _gnutls_x509_read_ecc_params(uint8_t * der, int dersize,
}
+/* Reads RSA-PSS parameters.
+ */
+int
+_gnutls_x509_read_rsa_pss_params(uint8_t * der, int dersize,
+ gnutls_x509_spki_st * params)
+{
+ int result;
+ ASN1_TYPE spk = ASN1_TYPE_EMPTY;
+ ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
+ gnutls_digest_algorithm_t digest;
+ char oid[MAX_OID_SIZE];
+ int size;
+ unsigned int trailer;
+ gnutls_datum_t value = { NULL, 0 };
+
+ if ((result = asn1_create_element
+ (_gnutls_get_gnutls_asn(), "GNUTLS.RSAPSSParameters", &spk))
+ != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ result = _asn1_strict_der_decode(&spk, der, dersize, NULL);
+
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ size = sizeof(oid);
+ result = asn1_read_value(spk, "hashAlgorithm.algorithm", oid, &size);
+ if (result == ASN1_SUCCESS)
+ digest = gnutls_oid_to_digest(oid);
+ else if (result == ASN1_ELEMENT_NOT_FOUND)
+ /* The default hash algorithm is SHA-1 */
+ digest = GNUTLS_DIG_SHA1;
+ else {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ size = sizeof(oid);
+ result = asn1_read_value(spk, "maskGenAlgorithm.algorithm", oid, &size);
+ if (result == ASN1_SUCCESS) {
+ gnutls_digest_algorithm_t digest2;
+
+ /* Error out if algorithm other than mgf1 is specified */
+ if (strcmp(oid, PKIX1_RSA_PSS_MGF1_OID) != 0) {
+ gnutls_assert();
+ result = GNUTLS_E_INVALID_REQUEST;
+ goto cleanup;
+ }
+
+ /* Check if maskGenAlgorithm.parameters does exist and
+ * is identical to hashAlgorithm */
+ result = _gnutls_x509_read_value(spk, "maskGenAlgorithm.parameters", &value);
+ if (result < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ if ((result = asn1_create_element
+ (_gnutls_get_pkix(), "PKIX1.AlgorithmIdentifier", &c2))
+ != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ result = _asn1_strict_der_decode(&c2, value.data, value.size, NULL);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ size = sizeof(oid);
+ result = asn1_read_value(c2, "algorithm", oid, &size);
+ if (result == ASN1_SUCCESS)
+ digest2 = gnutls_oid_to_digest(oid);
+ else if (result == ASN1_ELEMENT_NOT_FOUND)
+ /* The default hash algorithm for mgf1 is SHA-1 */
+ digest2 = GNUTLS_DIG_SHA1;
+ else {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ if (digest != digest2) {
+ gnutls_assert();
+ result = GNUTLS_E_INVALID_REQUEST;
+ goto cleanup;
+ }
+ } else if (result != ASN1_ELEMENT_NOT_FOUND) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ memset(params, 0, sizeof(gnutls_x509_spki_st));
+ params->pk = GNUTLS_PK_RSA_PSS;
+ params->dig = digest;
+
+ result = _gnutls_x509_read_uint(spk, "saltLength", &params->salt_size);
+ if (result == GNUTLS_E_ASN1_ELEMENT_NOT_FOUND ||
+ result == GNUTLS_E_ASN1_VALUE_NOT_FOUND)
+ params->salt_size = 20;
+ else if (result < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ result = _gnutls_x509_read_uint(spk, "trailerField", &trailer);
+ if (result == GNUTLS_E_ASN1_VALUE_NOT_FOUND ||
+ result == GNUTLS_E_ASN1_ELEMENT_NOT_FOUND)
+ trailer = 1;
+ else if (result < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+ if (trailer != 1) {
+ gnutls_assert();
+ result = GNUTLS_E_CERTIFICATE_ERROR;
+ goto cleanup;
+ }
+
+ result = 0;
+ cleanup:
+ _gnutls_free_datum(&value);
+ asn1_delete_structure(&c2);
+ asn1_delete_structure(&spk);
+ return result;
+}
+
/* This function must be called after _gnutls_x509_read_params()
*/
int _gnutls_x509_read_pubkey(gnutls_pk_algorithm_t algo, uint8_t * der,
@@ -243,9 +381,10 @@ int _gnutls_x509_read_pubkey(gnutls_pk_algorithm_t algo, uint8_t * der,
switch (algo) {
case GNUTLS_PK_RSA:
+ case GNUTLS_PK_RSA_PSS:
ret = _gnutls_x509_read_rsa_pubkey(der, dersize, params);
if (ret >= 0) {
- params->algo = GNUTLS_PK_RSA;
+ params->algo = algo;
params->params_nr = RSA_PUBLIC_PARAMS;
}
break;
@@ -282,6 +421,8 @@ int _gnutls_x509_read_pubkey_params(gnutls_pk_algorithm_t algo,
switch (algo) {
case GNUTLS_PK_RSA:
return 0;
+ case GNUTLS_PK_RSA_PSS:
+ return _gnutls_x509_read_rsa_pss_params(der, dersize, &params->sign);
case GNUTLS_PK_DSA:
return _gnutls_x509_read_dsa_params(der, dersize, params);
case GNUTLS_PK_EC:
@@ -291,6 +432,34 @@ int _gnutls_x509_read_pubkey_params(gnutls_pk_algorithm_t algo,
}
}
+/* This function must be called after _gnutls_x509_read_pubkey()
+ */
+int _gnutls_x509_check_pubkey_params(gnutls_pk_algorithm_t algo,
+ gnutls_pk_params_st * params)
+{
+ switch (algo) {
+ case GNUTLS_PK_RSA_PSS: {
+ unsigned bits = pubkey_to_bits(algo, params);
+ const mac_entry_st *me = hash_to_entry(params->sign.dig);
+ size_t hash_size;
+
+ if (unlikely(me == NULL))
+ return gnutls_assert_val(GNUTLS_E_CERTIFICATE_ERROR);
+
+ hash_size = _gnutls_hash_get_algo_len(me);
+ if (hash_size + params->sign.salt_size + 2 > (bits + 7) / 8)
+ return gnutls_assert_val(GNUTLS_E_CERTIFICATE_ERROR);
+ return 0;
+ }
+ case GNUTLS_PK_RSA:
+ case GNUTLS_PK_DSA:
+ case GNUTLS_PK_EC:
+ return 0;
+ default:
+ return gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE);
+ }
+}
+
/* reads DSA's Y
* from the certificate
* only sets params[3]
diff --git a/lib/x509/key_encode.c b/lib/x509/key_encode.c
index 3277ca2476..724f7402d9 100644
--- a/lib/x509/key_encode.c
+++ b/lib/x509/key_encode.c
@@ -144,6 +144,8 @@ _gnutls_x509_write_pubkey_params(gnutls_pk_algorithm_t algo,
memcpy(der->data, ASN1_NULL, ASN1_NULL_SIZE);
der->size = ASN1_NULL_SIZE;
return 0;
+ case GNUTLS_PK_RSA_PSS:
+ return _gnutls_x509_write_rsa_pss_params(&params->sign, der);
case GNUTLS_PK_EC:
return _gnutls_x509_write_ecc_params(params->flags, der);
default:
@@ -160,6 +162,7 @@ _gnutls_x509_write_pubkey(gnutls_pk_algorithm_t algo,
case GNUTLS_PK_DSA:
return _gnutls_x509_write_dsa_pubkey(params, der);
case GNUTLS_PK_RSA:
+ case GNUTLS_PK_RSA_PSS:
return _gnutls_x509_write_rsa_pubkey(params, der);
case GNUTLS_PK_EC:
return _gnutls_x509_write_ecc_pubkey(params, der);
@@ -285,6 +288,117 @@ _gnutls_x509_write_ecc_params(gnutls_ecc_curve_t curve,
return result;
}
+int
+_gnutls_x509_write_rsa_pss_params(gnutls_x509_spki_st *params,
+ gnutls_datum_t *der)
+{
+ int result;
+ ASN1_TYPE spk = ASN1_TYPE_EMPTY;
+ ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
+ const char *oid;
+ gnutls_datum_t tmp = { NULL, 0 };
+
+ der->data = NULL;
+ der->size = 0;
+
+ if ((result = asn1_create_element
+ (_gnutls_get_gnutls_asn(), "GNUTLS.RSAPSSParameters", &spk))
+ != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ oid = gnutls_digest_get_oid(params->dig);
+
+ if ((result = asn1_write_value(spk, "hashAlgorithm.algorithm", oid, 1))
+ != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ if ((result = asn1_write_value(spk, "hashAlgorithm.parameters", NULL, 0))
+ != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ if ((result =
+ asn1_write_value(spk, "maskGenAlgorithm.algorithm",
+ PKIX1_RSA_PSS_MGF1_OID, 1))
+ != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ if ((result = asn1_create_element
+ (_gnutls_get_pkix(), "PKIX1.AlgorithmIdentifier", &c2))
+ != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ if ((result = asn1_write_value(c2, "algorithm", oid, 1))
+ != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ if ((result = asn1_write_value(c2, "parameters", NULL, 0))
+ != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ result = _gnutls_x509_der_encode(c2, "", &tmp, 0);
+ if (result < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ if ((result =
+ asn1_write_value(spk, "maskGenAlgorithm.parameters",
+ tmp.data, tmp.size))
+ != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ result = _gnutls_x509_write_uint32(spk, "saltLength",
+ params->salt_size);
+ if (result < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ result = _gnutls_x509_write_uint32(spk, "trailerField", 1);
+ if (result < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ result = _gnutls_x509_der_encode(spk, "", der, 0);
+ if (result < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ result = 0;
+
+ cleanup:
+ _gnutls_free_datum(&tmp);
+ asn1_delete_structure(&c2);
+ asn1_delete_structure(&spk);
+ return result;
+}
+
/*
* This function writes the public parameters for DSS keys.
* Needs 1 parameter (y).
@@ -681,6 +795,7 @@ int _gnutls_asn1_encode_privkey(gnutls_pk_algorithm_t pk, ASN1_TYPE * c2,
{
switch (pk) {
case GNUTLS_PK_RSA:
+ case GNUTLS_PK_RSA_PSS:
return _gnutls_asn1_encode_rsa(c2, params, compat);
case GNUTLS_PK_DSA:
return _gnutls_asn1_encode_dsa(c2, params, compat);
diff --git a/lib/x509/mpi.c b/lib/x509/mpi.c
index 2bb3e54aaa..bd47d3244c 100644
--- a/lib/x509/mpi.c
+++ b/lib/x509/mpi.c
@@ -134,7 +134,7 @@ _gnutls_get_asn_mpis(ASN1_TYPE asn, const char *root,
* then the issuer's parameters should be used. This is not
* done yet.
*/
- if (pk_algorithm != GNUTLS_PK_RSA) { /* RSA doesn't use parameters */
+ if (pk_algorithm != GNUTLS_PK_RSA) { /* RSA doesn't use parameters */
result = _gnutls_x509_read_value(asn, name, &tmp);
if (result < 0) {
gnutls_assert();
@@ -169,6 +169,12 @@ _gnutls_get_asn_mpis(ASN1_TYPE asn, const char *root,
goto error;
}
+ result = _gnutls_x509_check_pubkey_params(pk_algorithm, params);
+ if (result < 0) {
+ gnutls_assert();
+ goto error;
+ }
+
result = 0;
error:
@@ -205,16 +211,89 @@ _gnutls_x509_crq_get_mpis(gnutls_x509_crq_t cert,
}
/*
- * This function writes and encodes the parameters for DSS or RSA keys.
+ * This function reads and decodes the parameters for DSS or RSA keys.
* This is the "signatureAlgorithm" fields.
- *
- * If @legacy is non-zero then the legacy value for PKCS#7 signatures
- * will be written for RSA signatures.
*/
int
-_gnutls_x509_write_sig_params(ASN1_TYPE dst, const char *dst_name,
- gnutls_pk_algorithm_t pk_algorithm,
- gnutls_digest_algorithm_t dig, unsigned legacy)
+_gnutls_x509_read_sign_params(ASN1_TYPE src, const char *src_name,
+ gnutls_x509_spki_st *params)
+{
+ int result;
+ char name[128];
+ char oid[MAX_OID_SIZE];
+ int oid_size;
+
+ _gnutls_str_cpy(name, sizeof(name), src_name);
+ _gnutls_str_cat(name, sizeof(name), ".algorithm");
+
+ oid_size = sizeof(oid);
+ result = asn1_read_value(src, name, oid, &oid_size);
+
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ return _gnutls_asn2err(result);
+ }
+
+ if (strcmp (oid, PK_PKIX1_RSA_PSS_OID) == 0) {
+ gnutls_datum_t tmp = { NULL, 0 };
+
+ _gnutls_str_cpy(name, sizeof(name), src_name);
+ _gnutls_str_cat(name, sizeof(name), ".parameters");
+
+ result = _gnutls_x509_read_value(src, name, &tmp);
+ if (result < 0 &&
+ result != GNUTLS_E_ASN1_ELEMENT_NOT_FOUND &&
+ result != GNUTLS_E_ASN1_VALUE_NOT_FOUND) {
+ _gnutls_free_datum(&tmp);
+ return gnutls_assert_val(result);
+ }
+
+ result = _gnutls_x509_read_rsa_pss_params(tmp.data, tmp.size,
+ params);
+ _gnutls_free_datum(&tmp);
+
+ if (result < 0)
+ gnutls_assert();
+
+ return result;
+ } else {
+ memset(params, 0, sizeof(gnutls_x509_spki_st));
+
+ result = gnutls_oid_to_sign(oid);
+ if (result != GNUTLS_SIGN_UNKNOWN) {
+ params->pk = gnutls_sign_get_pk_algorithm(result);
+ params->dig = gnutls_sign_get_hash_algorithm(result);
+ }
+ }
+
+ return 0;
+}
+
+int
+_gnutls_x509_crt_read_sign_params(gnutls_x509_crt_t crt,
+ gnutls_x509_spki_st *params)
+{
+ return _gnutls_x509_read_sign_params(crt->cert,
+ "tbsCertificate."
+ "subjectPublicKeyInfo."
+ "algorithm",
+ params);
+}
+
+int
+_gnutls_x509_crq_read_sign_params(gnutls_x509_crq_t crt,
+ gnutls_x509_spki_st *params)
+{
+ return _gnutls_x509_read_sign_params(crt->crq,
+ "certificationRequestInfo."
+ "subjectPKInfo."
+ "algorithm",
+ params);
+}
+
+int
+_gnutls_x509_write_sign_params(ASN1_TYPE dst, const char *dst_name,
+ gnutls_x509_spki_st *params)
{
int result;
char name[128];
@@ -223,15 +302,18 @@ _gnutls_x509_write_sig_params(ASN1_TYPE dst, const char *dst_name,
_gnutls_str_cpy(name, sizeof(name), dst_name);
_gnutls_str_cat(name, sizeof(name), ".algorithm");
- if (legacy && pk_algorithm == GNUTLS_PK_RSA)
+ if (params->legacy && params->pk == GNUTLS_PK_RSA)
oid = PK_PKIX1_RSA_OID;
+ else if (params->pk == GNUTLS_PK_RSA_PSS)
+ oid = PK_PKIX1_RSA_PSS_OID;
else
- oid = gnutls_sign_get_oid(gnutls_pk_to_sign(pk_algorithm, dig));
+ oid = gnutls_sign_get_oid(gnutls_pk_to_sign(params->pk,
+ params->dig));
if (oid == NULL) {
gnutls_assert();
_gnutls_debug_log
("Cannot find OID for sign algorithm pk: %d dig: %d\n",
- (int) pk_algorithm, (int) dig);
+ (int) params->pk, (int) params->dig);
return GNUTLS_E_INVALID_REQUEST;
}
@@ -247,10 +329,24 @@ _gnutls_x509_write_sig_params(ASN1_TYPE dst, const char *dst_name,
_gnutls_str_cpy(name, sizeof(name), dst_name);
_gnutls_str_cat(name, sizeof(name), ".parameters");
- if (pk_algorithm == GNUTLS_PK_RSA)
+ if (params->pk == GNUTLS_PK_RSA)
result =
asn1_write_value(dst, name, ASN1_NULL, ASN1_NULL_SIZE);
- else
+ else if (params->pk == GNUTLS_PK_RSA_PSS) {
+ gnutls_datum_t tmp = { NULL, 0 };
+
+ if (params == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ result = _gnutls_x509_write_rsa_pss_params(params, &tmp);
+ if (result < 0)
+ return gnutls_assert_val(result);
+
+ result = asn1_write_value(dst, name, tmp.data, tmp.size);
+ _gnutls_free_datum(&tmp);
+ } else
result = asn1_write_value(dst, name, NULL, 0);
if (result != ASN1_SUCCESS && result != ASN1_ELEMENT_NOT_FOUND) {
diff --git a/lib/x509/output.c b/lib/x509/output.c
index 8ebb998ed2..6bcf68275d 100644
--- a/lib/x509/output.c
+++ b/lib/x509/output.c
@@ -1231,6 +1231,7 @@ print_pubkey(gnutls_buffer_st * str, const char *key_name,
(err, bits)), bits);
switch (pk) {
case GNUTLS_PK_RSA:
+ case GNUTLS_PK_RSA_PSS:
{
gnutls_datum_t m, e;
@@ -1394,6 +1395,59 @@ print_pubkey(gnutls_buffer_st * str, const char *key_name,
}
static int
+print_crt_sig_params(gnutls_buffer_st * str, gnutls_x509_crt_t crt,
+ gnutls_certificate_print_formats_t format)
+{
+ int ret;
+ gnutls_pk_algorithm_t pk;
+ gnutls_x509_spki_st params;
+ gnutls_sign_algorithm_t sign;
+
+ sign = gnutls_x509_crt_get_signature_algorithm(crt);
+ pk = gnutls_sign_get_pk_algorithm(sign);
+ if (pk == GNUTLS_PK_RSA_PSS) {
+ ret = _gnutls_x509_read_sign_params(crt->cert,
+ "signatureAlgorithm",
+ &params);
+ if (ret < 0) {
+ addf(str, "error: read_pss_params: %s\n",
+ gnutls_strerror(ret));
+ } else
+ addf(str, "\t\tSalt Length: %d\n", params.salt_size);
+ }
+
+ return 0;
+}
+
+static int
+print_crt_pubkey_params(gnutls_buffer_st * str, const char *key_name,
+ gnutls_x509_crt_t crt,
+ gnutls_certificate_print_formats_t format)
+{
+ int ret;
+ gnutls_pk_algorithm_t pk;
+ gnutls_x509_spki_st params;
+
+ ret = gnutls_x509_crt_get_pk_algorithm(crt, NULL);
+ if (ret < 0)
+ return ret;
+
+ pk = ret;
+
+ if (pk == GNUTLS_PK_RSA_PSS) {
+ ret = _gnutls_x509_crt_read_sign_params(crt, &params);
+ if (ret < 0)
+ return ret;
+ addf(str, _("\t%sPublic Key Parameters:\n"), key_name);
+ addf(str, "\t\tHash Algorithm: %s\n",
+ gnutls_digest_get_name(params.dig));
+ addf(str, "\t\tSalt Length: %d\n", params.salt_size);
+ }
+
+ return 0;
+}
+
+static int
print_crt_pubkey(gnutls_buffer_st * str, gnutls_x509_crt_t crt,
gnutls_certificate_print_formats_t format)
{
@@ -1409,6 +1463,7 @@ print_crt_pubkey(gnutls_buffer_st * str, gnutls_x509_crt_t crt,
goto cleanup;
print_pubkey(str, _("Subject "), pubkey, format);
+ print_crt_pubkey_params(str, _("Subject "), crt, format);
ret = 0;
cleanup:
@@ -1573,6 +1628,8 @@ print_cert(gnutls_buffer_st * str, gnutls_x509_crt_t cert,
addf(str, _("\tSignature Algorithm: %s\n"), p);
gnutls_free(name);
+ print_crt_sig_params(str, cert, format);
+
if (err != GNUTLS_SIGN_UNKNOWN && gnutls_sign_is_secure(err) == 0) {
adds(str,
_("warning: signed using a broken signature "
@@ -2287,6 +2344,58 @@ gnutls_x509_crl_print(gnutls_x509_crl_t crl,
}
static int
+print_crq_sig_params(gnutls_buffer_st * str, gnutls_x509_crq_t crt,
+ gnutls_certificate_print_formats_t format)
+{
+ int ret;
+ gnutls_pk_algorithm_t pk;
+ gnutls_x509_spki_st params;
+ gnutls_sign_algorithm_t sign;
+
+ sign = gnutls_x509_crq_get_signature_algorithm(crt);
+ pk = gnutls_sign_get_pk_algorithm(sign);
+ if (pk == GNUTLS_PK_RSA_PSS) {
+ ret = _gnutls_x509_read_sign_params(crt->crq,
+ "signatureAlgorithm",
+ &params);
+ if (ret < 0) {
+ addf(str, "error: read_pss_params: %s\n",
+ gnutls_strerror(ret));
+ } else
+ addf(str, "\t\tSalt Length: %d\n", params.salt_size);
+ }
+
+ return 0;
+}
+static int
+print_crq_pubkey_params(gnutls_buffer_st * str, const char *key_name,
+ gnutls_x509_crq_t crt,
+ gnutls_certificate_print_formats_t format)
+{
+ int ret;
+ gnutls_pk_algorithm_t pk;
+ gnutls_x509_spki_st params;
+
+ ret = gnutls_x509_crq_get_pk_algorithm(crt, NULL);
+ if (ret < 0)
+ return ret;
+
+ pk = ret;
+
+ if (pk == GNUTLS_PK_RSA_PSS) {
+ ret = _gnutls_x509_crq_read_sign_params(crt, &params);
+ if (ret < 0)
+ return ret;
+ addf(str, _("\t%sPublic Key Parameters:\n"), key_name);
+ addf(str, "\t\tHash Algorithm: %s\n",
+ gnutls_digest_get_name(params.dig));
+ addf(str, "\t\tSalt Length: %d\n", params.salt_size);
+ }
+
+ return 0;
+}
+
+static int
print_crq_pubkey(gnutls_buffer_st * str, gnutls_x509_crq_t crq,
gnutls_certificate_print_formats_t format)
{
@@ -2302,6 +2411,7 @@ print_crq_pubkey(gnutls_buffer_st * str, gnutls_x509_crq_t crq,
goto cleanup;
print_pubkey(str, _("Subject "), pubkey, format);
+ print_crq_pubkey_params(str, _("Subject "), crq, format);
ret = 0;
cleanup:
@@ -2369,6 +2479,8 @@ print_crq(gnutls_buffer_st * str, gnutls_x509_crq_t cert,
addf(str, _("\tSignature Algorithm: %s\n"), p);
gnutls_free(name);
+
+ print_crq_sig_params(str, cert, format);
}
/* parse attributes */
diff --git a/lib/x509/pkcs7.c b/lib/x509/pkcs7.c
index e285546060..9222af652e 100644
--- a/lib/x509/pkcs7.c
+++ b/lib/x509/pkcs7.c
@@ -2348,6 +2348,7 @@ int gnutls_pkcs7_sign(gnutls_pkcs7_t pkcs7,
gnutls_datum_t signature = { NULL, 0 };
const mac_entry_st *me = hash_to_entry(dig);
unsigned pk, sigalgo;
+ gnutls_x509_spki_st key_params, params;
if (pkcs7 == NULL || me == NULL)
return GNUTLS_E_INVALID_REQUEST;
@@ -2485,15 +2486,35 @@ int gnutls_pkcs7_sign(gnutls_pkcs7_t pkcs7,
/* write the signature algorithm */
pk = gnutls_x509_crt_get_pk_algorithm(signer, NULL);
+ ret = _gnutls_privkey_get_sign_params(signer_key, &key_params);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ ret = _gnutls_x509_crt_get_sign_params(signer, &key_params, &params);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ result = _gnutls_privkey_find_sign_params(signer_key, pk, dig, 0,
+ &params);
+ if (result < 0) {
+ gnutls_assert();
+ return result;
+ }
+
/* RFC5652 is silent on what the values would be and initially I assumed that
* typical signature algorithms should be set. However RFC2315 (PKCS#7) mentions
* that a generic RSA OID should be used. We switch to this "unexpected" value
* because some implementations cannot cope with the "expected" signature values.
*/
+ params.legacy = 1;
ret =
- _gnutls_x509_write_sig_params(pkcs7->signed_data,
- "signerInfos.?LAST.signatureAlgorithm",
- pk, dig, 1);
+ _gnutls_x509_write_sign_params(pkcs7->signed_data,
+ "signerInfos.?LAST.signatureAlgorithm",
+ &params);
if (ret < 0) {
gnutls_assert();
goto cleanup;
@@ -2515,8 +2536,7 @@ int gnutls_pkcs7_sign(gnutls_pkcs7_t pkcs7,
goto cleanup;
}
- ret =
- gnutls_privkey_sign_data(signer_key, dig, 0, &sigdata, &signature);
+ ret = privkey_sign_data(signer_key, &sigdata, &signature, &params);
if (ret < 0) {
gnutls_assert();
goto cleanup;
diff --git a/lib/x509/privkey.c b/lib/x509/privkey.c
index c88f4fa681..b8e6092c34 100644
--- a/lib/x509/privkey.c
+++ b/lib/x509/privkey.c
@@ -1202,6 +1202,26 @@ int
gnutls_x509_privkey_get_pk_algorithm2(gnutls_x509_privkey_t key,
unsigned int *bits)
{
+ return gnutls_x509_privkey_get_pk_algorithm3(key, NULL, bits);
+}
+
+/**
+ * gnutls_x509_privkey_get_pk_algorithm3:
+ * @key: should contain a #gnutls_x509_privkey_t type
+ * @spki: a SubjectPublicKeyInfo structure of type #gnutls_x509_spki_t
+ * @bits: The number of bits in the public key algorithm
+ *
+ * This function will return the public key algorithm of a private
+ * key.
+ *
+ * Returns: a member of the #gnutls_pk_algorithm_t enumeration on
+ * success, or a negative error code on error.
+ **/
+int
+gnutls_x509_privkey_get_pk_algorithm3(gnutls_x509_privkey_t key,
+ gnutls_x509_spki_t spki,
+ unsigned int *bits)
+{
int ret;
if (key == NULL) {
@@ -1209,6 +1229,10 @@ gnutls_x509_privkey_get_pk_algorithm2(gnutls_x509_privkey_t key,
return GNUTLS_E_INVALID_REQUEST;
}
+ if (spki) {
+ memcpy(spki, &key->params.sign, sizeof (gnutls_x509_spki_st));
+ }
+
if (bits) {
ret = pubkey_to_bits(key->pk_algorithm, &key->params);
if (ret < 0)
@@ -1221,7 +1245,7 @@ gnutls_x509_privkey_get_pk_algorithm2(gnutls_x509_privkey_t key,
static const char *set_msg(gnutls_x509_privkey_t key)
{
- if (key->pk_algorithm == GNUTLS_PK_RSA) {
+ if (GNUTLS_PK_IS_RSA(key->pk_algorithm)) {
if (key->params.seed_size > 0 && !(key->flags&GNUTLS_PRIVKEY_FLAG_EXPORT_COMPAT))
return PEM_KEY_RSA_PROVABLE;
else
@@ -1565,6 +1589,30 @@ gnutls_x509_privkey_generate2(gnutls_x509_privkey_t key,
return ret;
}
+ if (algo == GNUTLS_PK_RSA_PSS) {
+ const mac_entry_st *me;
+
+ key->params.sign.pk = GNUTLS_PK_RSA_PSS;
+ if (key->params.palgo != GNUTLS_DIG_UNKNOWN)
+ key->params.sign.dig = key->params.palgo;
+ else
+ key->params.sign.dig = GNUTLS_DIG_SHA256;
+
+ me = hash_to_entry(key->params.sign.dig);
+ if (unlikely(me == NULL)) {
+ gnutls_assert();
+ ret = GNUTLS_E_INVALID_REQUEST;
+ goto cleanup;
+ }
+
+ if (flags & GNUTLS_PRIVKEY_FLAG_PROVABLE)
+ key->params.sign.salt_size = 0;
+ else {
+ key->params.sign.salt_size =
+ _gnutls_find_rsa_pss_salt_size(bits, me, 0);
+ }
+ }
+
ret = _gnutls_pk_generate_keys(algo, bits, &key->params, 0);
if (ret < 0) {
gnutls_assert();
@@ -1930,7 +1978,7 @@ _gnutls_x509_privkey_sign_hash2(gnutls_x509_privkey_t signer,
ret =
_gnutls_pk_sign(signer->pk_algorithm, signature, &digest,
- &signer->params);
+ &signer->params, &signer->params.sign);
if (ret < 0) {
gnutls_assert();
@@ -1974,7 +2022,7 @@ gnutls_x509_privkey_sign_hash(gnutls_x509_privkey_t key,
result =
_gnutls_pk_sign(key->pk_algorithm, signature, hash,
- &key->params);
+ &key->params, &key->params.sign);
if (result < 0) {
gnutls_assert();
@@ -2130,3 +2178,66 @@ void gnutls_x509_privkey_set_flags(gnutls_x509_privkey_t key,
{
key->flags |= flags;
}
+
+int
+_gnutls_x509_privkey_get_sign_params(gnutls_x509_privkey_t key,
+ gnutls_x509_spki_st *params)
+{
+ memcpy(params, &key->params.sign, sizeof(gnutls_x509_spki_st));
+ params->pk = gnutls_x509_privkey_get_pk_algorithm2(key, NULL);
+ return 0;
+}
+
+int
+_gnutls_x509_privkey_find_sign_params(gnutls_x509_privkey_t key,
+ gnutls_pk_algorithm_t pk,
+ gnutls_digest_algorithm_t dig,
+ unsigned flags,
+ gnutls_x509_spki_st *params)
+{
+ unsigned salt_size = 0;
+ gnutls_pk_algorithm_t key_pk;
+ unsigned bits;
+
+ if (flags & GNUTLS_PRIVKEY_SIGN_FLAG_RSA_PSS) {
+ if (!GNUTLS_PK_IS_RSA(pk))
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+ pk = GNUTLS_PK_RSA_PSS;
+ }
+
+ key_pk = gnutls_x509_privkey_get_pk_algorithm2(key, &bits);
+ if (!(key_pk == pk ||
+ (key_pk == GNUTLS_PK_RSA && pk == GNUTLS_PK_RSA_PSS))) {
+ gnutls_assert();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ if (pk == GNUTLS_PK_RSA_PSS) {
+ const mac_entry_st *me;
+
+ me = hash_to_entry(dig);
+ if (unlikely(me == NULL))
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+ if (params->pk == GNUTLS_PK_RSA)
+ salt_size = 0;
+ else if (params->pk == GNUTLS_PK_RSA_PSS) {
+ if (dig != params->dig) {
+ gnutls_assert();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ salt_size = params->salt_size;
+ }
+
+ if ((flags & GNUTLS_PRIVKEY_SIGN_FLAG_REPRODUCIBLE) == 0)
+ salt_size = _gnutls_find_rsa_pss_salt_size(bits, me,
+ salt_size);
+ }
+
+ params->pk = pk;
+ params->dig = dig;
+ params->salt_size = salt_size;
+
+ return 0;
+}
diff --git a/lib/x509/privkey_pkcs8.c b/lib/x509/privkey_pkcs8.c
index 0f1863d160..827794bec2 100644
--- a/lib/x509/privkey_pkcs8.c
+++ b/lib/x509/privkey_pkcs8.c
@@ -67,6 +67,7 @@ _encode_privkey(gnutls_x509_privkey_t pkey, gnutls_datum_t * raw)
switch (pkey->pk_algorithm) {
case GNUTLS_PK_RSA:
+ case GNUTLS_PK_RSA_PSS:
case GNUTLS_PK_EC:
ret =
gnutls_x509_privkey_export2(pkey, GNUTLS_X509_FMT_DER,
@@ -939,6 +940,44 @@ _decode_pkcs8_rsa_key(ASN1_TYPE pkcs8_asn, gnutls_x509_privkey_t pkey)
return ret;
}
+/* Decodes an RSA-PSS privateKey from a PKCS8 structure.
+ */
+static int
+_decode_pkcs8_rsa_pss_key(ASN1_TYPE pkcs8_asn, gnutls_x509_privkey_t pkey)
+{
+ int ret;
+ gnutls_datum_t tmp;
+ gnutls_x509_spki_st params;
+
+ ret = _gnutls_x509_read_value(pkcs8_asn,
+ "privateKeyAlgorithm.parameters", &tmp);
+ if (ret < 0) {
+ gnutls_assert();
+ goto error;
+ }
+
+ ret = _gnutls_x509_read_rsa_pss_params(tmp.data, tmp.size, &params);
+ _gnutls_free_key_datum(&tmp);
+
+ if (ret < 0) {
+ gnutls_assert();
+ goto error;
+ }
+
+ ret = _decode_pkcs8_rsa_key(pkcs8_asn, pkey);
+ if (ret < 0) {
+ gnutls_assert();
+ goto error;
+ }
+
+ memcpy(&pkey->params.sign, &params, sizeof(gnutls_x509_spki_st));
+
+ ret = 0;
+
+ error:
+ return ret;
+}
+
/* Decodes an ECC privateKey from a PKCS8 structure.
*/
static int
@@ -1120,6 +1159,8 @@ decode_private_key_info(const gnutls_datum_t * der,
if (pkey->pk_algorithm == GNUTLS_PK_RSA)
result = _decode_pkcs8_rsa_key(pkcs8_asn, pkey);
+ else if (pkey->pk_algorithm == GNUTLS_PK_RSA_PSS)
+ result = _decode_pkcs8_rsa_pss_key(pkcs8_asn, pkey);
else if (pkey->pk_algorithm == GNUTLS_PK_DSA)
result = _decode_pkcs8_dsa_key(pkcs8_asn, pkey);
else if (pkey->pk_algorithm == GNUTLS_PK_EC)
diff --git a/lib/x509/sign.c b/lib/x509/sign.c
index 35e57f01a2..0abe92a3b4 100644
--- a/lib/x509/sign.c
+++ b/lib/x509/sign.c
@@ -36,6 +36,7 @@
#include <x509_int.h>
#include <common.h>
#include <gnutls/abstract.h>
+#include <pk.h>
/* This is the same as the _gnutls_x509_sign, but this one will decode
* the ASN1_TYPE given, and sign the DER data. Actually used to get the DER
@@ -48,6 +49,43 @@ _gnutls_x509_get_tbs(ASN1_TYPE cert, const char *tbs_name,
return _gnutls_x509_der_encode(cert, tbs_name, tbs, 0);
}
+int
+_gnutls_x509_crt_get_sign_params(gnutls_x509_crt_t crt,
+ const gnutls_x509_spki_st *key_params,
+ gnutls_x509_spki_st *params)
+{
+ int result;
+ gnutls_x509_spki_st crt_params;
+
+ result = _gnutls_x509_crt_read_sign_params(crt, &crt_params);
+ if (result < 0) {
+ gnutls_assert();
+ return result;
+ }
+
+ if (crt_params.pk == GNUTLS_PK_RSA_PSS) {
+ if (key_params->pk == GNUTLS_PK_RSA_PSS) {
+ if (crt_params.dig != key_params->dig) {
+ gnutls_assert();
+ return GNUTLS_E_CERTIFICATE_ERROR;
+ }
+
+ if (crt_params.salt_size < key_params->salt_size) {
+ gnutls_assert();
+ return GNUTLS_E_CERTIFICATE_ERROR;
+ }
+ } else if (key_params->pk != GNUTLS_PK_RSA) {
+ gnutls_assert();
+ return GNUTLS_E_CERTIFICATE_ERROR;
+ }
+ memcpy(params, &crt_params, sizeof(gnutls_x509_spki_st));
+ } else {
+ memcpy(params, key_params, sizeof(gnutls_x509_spki_st));
+ }
+
+ return 0;
+}
+
/*-
* _gnutls_x509_pkix_sign - This function will sign a CRL or a certificate with a key
* @src: should contain an ASN1_TYPE
@@ -63,6 +101,7 @@ _gnutls_x509_get_tbs(ASN1_TYPE cert, const char *tbs_name,
int
_gnutls_x509_pkix_sign(ASN1_TYPE src, const char *src_name,
gnutls_digest_algorithm_t dig,
+ unsigned int flags,
gnutls_x509_crt_t issuer,
gnutls_privkey_t issuer_key)
{
@@ -70,6 +109,31 @@ _gnutls_x509_pkix_sign(ASN1_TYPE src, const char *src_name,
gnutls_datum_t signature;
gnutls_datum_t tbs;
char name[128];
+ gnutls_pk_algorithm_t pk;
+ gnutls_x509_spki_st key_params, params;
+
+ pk = gnutls_x509_crt_get_pk_algorithm(issuer, NULL);
+ if (pk == GNUTLS_PK_UNKNOWN)
+ pk = gnutls_privkey_get_pk_algorithm(issuer_key, NULL);
+
+ result = _gnutls_privkey_get_sign_params(issuer_key, &key_params);
+ if (result < 0) {
+ gnutls_assert();
+ return result;
+ }
+
+ result = _gnutls_x509_crt_get_sign_params(issuer, &key_params, &params);
+ if (result < 0) {
+ gnutls_assert();
+ return result;
+ }
+
+ result = _gnutls_privkey_find_sign_params(issuer_key, pk, dig, flags,
+ &params);
+ if (result < 0) {
+ gnutls_assert();
+ return result;
+ }
/* Step 1. Copy the issuer's name into the certificate.
*/
@@ -89,9 +153,7 @@ _gnutls_x509_pkix_sign(ASN1_TYPE src, const char *src_name,
_gnutls_str_cpy(name, sizeof(name), src_name);
_gnutls_str_cat(name, sizeof(name), ".signature");
- result = _gnutls_x509_write_sig_params(src, name,
- gnutls_privkey_get_pk_algorithm
- (issuer_key, NULL), dig, 0);
+ result = _gnutls_x509_write_sign_params(src, name, &params);
if (result < 0) {
gnutls_assert();
return result;
@@ -106,8 +168,7 @@ _gnutls_x509_pkix_sign(ASN1_TYPE src, const char *src_name,
return result;
}
- result =
- gnutls_privkey_sign_data(issuer_key, dig, 0, &tbs, &signature);
+ result = privkey_sign_data(issuer_key, &tbs, &signature, &params);
gnutls_free(tbs.data);
if (result < 0) {
@@ -132,9 +193,8 @@ _gnutls_x509_pkix_sign(ASN1_TYPE src, const char *src_name,
* the same.
*/
- result = _gnutls_x509_write_sig_params(src, "signatureAlgorithm",
- gnutls_privkey_get_pk_algorithm
- (issuer_key, NULL), dig, 0);
+ result = _gnutls_x509_write_sign_params(src, "signatureAlgorithm",
+ &params);
if (result < 0) {
gnutls_assert();
return result;
diff --git a/lib/x509/spki.c b/lib/x509/spki.c
new file mode 100644
index 0000000000..af94ea4a2a
--- /dev/null
+++ b/lib/x509/spki.c
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * Authors: Daiki Ueno
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "gnutls_int.h"
+#include "errors.h"
+#include <common.h>
+#include <x509.h>
+#include <x509_int.h>
+
+/**
+ * gnutls_x509_spki_init:
+ * @spki: A pointer to the type to be initialized
+ *
+ * This function will initialize a SubjectPublicKeyInfo structure used
+ * in PKIX. The structure is used to set additional parameters
+ * in the public key information field of a certificate.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
+ * negative error value.
+ *
+ * Since: 3.6.0
+ *
+ **/
+int
+gnutls_x509_spki_init(gnutls_x509_spki_t *spki)
+{
+ gnutls_x509_spki_t tmp;
+
+ FAIL_IF_LIB_ERROR;
+
+ tmp =
+ gnutls_calloc(1, sizeof(gnutls_x509_spki_st));
+
+ if (!tmp)
+ return GNUTLS_E_MEMORY_ERROR;
+
+ *spki = tmp;
+
+ return 0; /* success */
+}
+
+/**
+ * gnutls_x509_spki_deinit:
+ * @spki: the SubjectPublicKeyInfo structure
+ *
+ * This function will deinitialize a SubjectPublicKeyInfo structure.
+ *
+ * Since: 3.6.0
+ *
+ **/
+void
+gnutls_x509_spki_deinit(gnutls_x509_spki_t spki)
+{
+ gnutls_free(spki);
+}
+
+/**
+ * gnutls_x509_spki_set_pk_algorithm:
+ * @spki: the SubjectPublicKeyInfo structure
+ * @pk: the public key algorithm of type #gnutls_pk_algorithm_t
+ *
+ * This function will set the public key algorithm of a
+ * SubjectPublicKeyInfo structure.
+ *
+ * Since: 3.6.0
+ *
+ **/
+void
+gnutls_x509_spki_set_pk_algorithm(gnutls_x509_spki_t spki,
+ gnutls_pk_algorithm_t pk)
+{
+ spki->pk = pk;
+}
+
+/**
+ * gnutls_x509_spki_get_pk_algorithm:
+ * @spki: the SubjectPublicKeyInfo structure
+ *
+ * This function will get the public key algorithm of a
+ * SubjectPublicKeyInfo structure.
+ *
+ * Returns: a member of the #gnutls_pk_algorithm_t enumeration on
+ * success, or %GNUTLS_PK_UNKNOWN on error.
+ *
+ * Since: 3.6.0
+ *
+ **/
+int
+gnutls_x509_spki_get_pk_algorithm(gnutls_x509_spki_t spki)
+{
+ return spki->pk;
+}
+
+/**
+ * gnutls_x509_spki_set_digest_algorithm:
+ * @spki: the SubjectPublicKeyInfo structure
+ * @dig: the digest algorithm of type #gnutls_digest_algorithm_t
+ *
+ * This function will set the digest algorithm of a
+ * SubjectPublicKeyInfo structure.
+ *
+ * Since: 3.6.0
+ *
+ **/
+void
+gnutls_x509_spki_set_digest_algorithm(gnutls_x509_spki_t spki,
+ gnutls_digest_algorithm_t dig)
+{
+ spki->dig = dig;
+}
+
+/**
+ * gnutls_x509_spki_get_digest_algorithm:
+ * @spki: the SubjectPublicKeyInfo structure
+ *
+ * This function will get the digest algorithm of a
+ * SubjectPublicKeyInfo structure.
+ *
+ * Returns: a member of the #gnutls_digest_algorithm_t enumeration on
+ * success, or a %GNUTLS_DIG_UNKNOWN on error.
+ *
+ * Since: 3.6.0
+ *
+ **/
+int
+gnutls_x509_spki_get_digest_algorithm(gnutls_x509_spki_t spki)
+{
+ return spki->dig;
+}
+
+/**
+ * gnutls_x509_spki_set_salt_size:
+ * @spki: the SubjectPublicKeyInfo structure
+ * @salt_size: the size of salt string
+ *
+ * This function will set the salt size parameter of a
+ * SubjectPublicKeyInfo structure.
+ *
+ * The salt is used in the RSA-PSS signature scheme.
+ *
+ * Since: 3.6.0
+ *
+ **/
+void
+gnutls_x509_spki_set_salt_size(gnutls_x509_spki_t spki,
+ unsigned int salt_size)
+{
+ spki->salt_size = salt_size;
+}
+
+/**
+ * gnutls_x509_spki_get_salt_size:
+ * @spki: the SubjectPublicKeyInfo structure
+ *
+ * This function will get the salt size parameter of a
+ * SubjectPublicKeyInfo structure.
+ *
+ * The salt is used in the RSA-PSS signature scheme.
+ *
+ * Returns: salt size as a positive integer, or zero.
+ *
+ * Since: 3.6.0
+ *
+ **/
+int
+gnutls_x509_spki_get_salt_size(gnutls_x509_spki_t spki)
+{
+ return spki->salt_size;
+}
diff --git a/lib/x509/verify.c b/lib/x509/verify.c
index 041c22066b..e27c5dfdaa 100644
--- a/lib/x509/verify.c
+++ b/lib/x509/verify.c
@@ -579,6 +579,12 @@ typedef struct verify_state_st {
out |= (x|GNUTLS_CERT_INVALID); \
result = 0; }
+static int _gnutls_x509_verify_data(gnutls_sign_algorithm_t sign,
+ const gnutls_datum_t * data,
+ const gnutls_datum_t * signature,
+ gnutls_x509_crt_t cert,
+ gnutls_x509_crt_t issuer);
+
/*
* Verifies the given certificate against a certificate list of
* trusted CAs.
@@ -602,9 +608,8 @@ verify_crt(gnutls_x509_crt_t cert,
gnutls_datum_t cert_signed_data = { NULL, 0 };
gnutls_datum_t cert_signature = { NULL, 0 };
gnutls_x509_crt_t issuer = NULL;
- int issuer_version, hash_algo;
+ int issuer_version;
unsigned result = 1;
- const mac_entry_st * me;
unsigned int out = 0, usage;
int sigalg, ret;
@@ -639,7 +644,7 @@ verify_crt(gnutls_x509_crt_t cert,
ret =
_gnutls_x509_get_signature_algorithm(cert->cert,
- "signatureAlgorithm.algorithm");
+ "signatureAlgorithm");
if (ret < 0) {
MARK_INVALID(0);
}
@@ -733,22 +738,17 @@ verify_crt(gnutls_x509_crt_t cert,
}
}
- if (sigalg >= 0) {
- hash_algo = gnutls_sign_get_hash_algorithm(sigalg);
- me = mac_to_entry(hash_algo);
- } else {
- me = NULL;
- }
-
- if (me == NULL) {
+ if (sigalg < 0) {
MARK_INVALID(0);
} else if (cert_signed_data.data != NULL &&
- cert_signature.data != NULL) {
+ cert_signature.data != NULL) {
ret =
- _gnutls_x509_verify_data(me,
+ _gnutls_x509_verify_data(sigalg,
&cert_signed_data,
&cert_signature,
+ cert,
issuer);
+
if (ret == GNUTLS_E_PK_SIG_VERIFY_FAILED) {
MARK_INVALID(GNUTLS_CERT_SIGNATURE_FAILURE);
} else if (ret < 0) {
@@ -1273,6 +1273,45 @@ cleanup:
}
#endif
+static int
+_gnutls_x509_validate_sign_params(gnutls_pk_algorithm_t pk_algorithm,
+ ASN1_TYPE cert,
+ const char *name,
+ gnutls_x509_spki_st *sig_params)
+{
+ /* The signature parameter validation is only needed for RSA-PSS */
+ if (pk_algorithm == GNUTLS_PK_RSA_PSS) {
+ int result;
+ gnutls_x509_spki_st params;
+
+ result = _gnutls_x509_read_sign_params(cert, name, &params);
+ if (result < 0) {
+ /* If parameters field is absent, no parameter
+ * validation is needed */
+ if (result != GNUTLS_E_ASN1_ELEMENT_NOT_FOUND &&
+ result != GNUTLS_E_ASN1_VALUE_NOT_FOUND) {
+ gnutls_assert();
+ return result;
+ }
+ } else {
+ /* Check if the underlying hash algorithms are same. */
+ if (sig_params->dig != params.dig) {
+ gnutls_assert();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ /* The salt length used to generate the
+ * signature must be equal to or larger than
+ * the one in the key parameter. */
+ if (sig_params->salt_size < params.salt_size) {
+ gnutls_assert();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+ }
+ }
+ return 0;
+}
+
/* verifies if the certificate is properly signed.
* returns GNUTLS_E_PK_VERIFY_SIG_FAILED on failure and 1 on success.
*
@@ -1280,33 +1319,71 @@ cleanup:
* 'signature' is the signature!
*/
int
-_gnutls_x509_verify_data(const mac_entry_st * me,
+_gnutls_x509_verify_data(gnutls_sign_algorithm_t sign,
const gnutls_datum_t * data,
const gnutls_datum_t * signature,
+ gnutls_x509_crt_t cert,
gnutls_x509_crt_t issuer)
{
- gnutls_pk_params_st issuer_params;
+ gnutls_pk_params_st params;
+ gnutls_pk_algorithm_t issuer_pk;
int ret;
+ gnutls_x509_spki_st sign_params;
+ const mac_entry_st * me;
/* Read the MPI parameters from the issuer's certificate.
*/
- ret = _gnutls_x509_crt_get_mpis(issuer, &issuer_params);
+ ret = _gnutls_x509_crt_get_mpis(issuer, &params);
if (ret < 0) {
gnutls_assert();
return ret;
}
- ret =
- pubkey_verify_data(gnutls_x509_crt_get_pk_algorithm
- (issuer, NULL), me, data, signature,
- &issuer_params);
+ issuer_pk = gnutls_x509_crt_get_pk_algorithm(issuer, NULL);
+
+ if (cert != NULL) {
+ ret = _gnutls_x509_read_sign_params(cert->cert,
+ "signatureAlgorithm",
+ &sign_params);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ ret = _gnutls_x509_validate_sign_params(issuer_pk,
+ issuer->cert,
+ "tbsCertificate."
+ "subjectPublicKeyInfo."
+ "algorithm",
+ &sign_params);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+ } else {
+ memcpy(&sign_params, &params.sign,
+ sizeof(gnutls_x509_spki_st));
+ sign_params.pk = gnutls_sign_get_pk_algorithm(sign);
+ sign_params.dig = gnutls_sign_get_hash_algorithm(sign);
+ }
+
+ me = hash_to_entry(sign_params.dig);
+ if (unlikely(me == NULL)) {
+ gnutls_assert();
+ ret = GNUTLS_E_CERTIFICATE_ERROR;
+ goto cleanup;
+ }
+
+ ret = pubkey_verify_data(sign_params.pk, me, data, signature, &params,
+ &sign_params);
if (ret < 0) {
gnutls_assert();
}
+ cleanup:
/* release all allocated MPIs
*/
- gnutls_pk_params_release(&issuer_params);
+ gnutls_pk_params_release(&params);
return ret;
}
@@ -1477,7 +1554,7 @@ gnutls_x509_crl_verify(gnutls_x509_crl_t crl,
gnutls_datum_t crl_signed_data = { NULL, 0 };
gnutls_datum_t crl_signature = { NULL, 0 };
gnutls_x509_crt_t issuer = NULL;
- int result, hash_algo;
+ int result, sigalg;
time_t now = gnutls_time(0);
unsigned int usage;
@@ -1507,18 +1584,16 @@ gnutls_x509_crl_verify(gnutls_x509_crl_t crl,
goto cleanup;
}
- result =
+ sigalg =
_gnutls_x509_get_signature_algorithm(crl->crl,
- "signatureAlgorithm.algorithm");
- if (result < 0) {
+ "signatureAlgorithm");
+ if (sigalg < 0) {
gnutls_assert();
if (verify)
*verify |= GNUTLS_CERT_INVALID;
goto cleanup;
}
- hash_algo = gnutls_sign_get_hash_algorithm(result);
-
/* issuer is not in trusted certificate
* authorities.
*/
@@ -1556,8 +1631,9 @@ gnutls_x509_crl_verify(gnutls_x509_crl_t crl,
}
result =
- _gnutls_x509_verify_data(mac_to_entry(hash_algo),
+ _gnutls_x509_verify_data(sigalg,
&crl_signed_data, &crl_signature,
+ NULL,
issuer);
if (result == GNUTLS_E_PK_SIG_VERIFY_FAILED) {
gnutls_assert();
@@ -1576,8 +1652,6 @@ gnutls_x509_crl_verify(gnutls_x509_crl_t crl,
}
{
- int sigalg;
-
sigalg = gnutls_x509_crl_get_signature_algorithm(crl);
if (((sigalg == GNUTLS_SIGN_RSA_MD2) &&
diff --git a/lib/x509/x509.c b/lib/x509/x509.c
index 93e79cb298..f346c93b3b 100644
--- a/lib/x509/x509.c
+++ b/lib/x509/x509.c
@@ -303,14 +303,14 @@ static int compare_sig_algorithm(gnutls_x509_crt_t cert)
unsigned empty1 = 0, empty2 = 0;
ret = _gnutls_x509_get_signature_algorithm(cert->cert,
- "signatureAlgorithm.algorithm");
+ "signatureAlgorithm");
if (ret < 0) {
gnutls_assert();
return ret;
}
s2 = _gnutls_x509_get_signature_algorithm(cert->cert,
- "tbsCertificate.signature.algorithm");
+ "tbsCertificate.signature");
if (ret != s2) {
_gnutls_debug_log("signatureAlgorithm.algorithm differs from tbsCertificate.signature.algorithm: %s, %s\n",
gnutls_sign_get_name(ret), gnutls_sign_get_name(s2));
@@ -982,7 +982,7 @@ gnutls_x509_crt_get_dn_oid(gnutls_x509_crt_t cert,
int gnutls_x509_crt_get_signature_algorithm(gnutls_x509_crt_t cert)
{
return _gnutls_x509_get_signature_algorithm(cert->cert,
- "signatureAlgorithm.algorithm");
+ "signatureAlgorithm");
}
/**
@@ -1548,6 +1548,37 @@ int
gnutls_x509_crt_get_pk_algorithm(gnutls_x509_crt_t cert,
unsigned int *bits)
{
+ return gnutls_x509_crt_get_pk_algorithm2(cert, NULL, bits);
+}
+
+/**
+ * gnutls_x509_crt_get_pk_algorithm2:
+ * @cert: a certificate of type #gnutls_x509_crt_t
+ * @spki: a SubjectPublicKeyInfo structure of type #gnutls_x509_spki_t
+ * @bits: if bits is non null it will hold the size of the parameters' in bits
+ *
+ * This function will return the public key algorithm of an X.509
+ * certificate.
+ *
+ * If @spki is non null, it should have enough size to hold the
+ * parameters.
+ *
+ * If @bits is non null, it should have enough size to hold the
+ * parameters size in bits. For RSA the bits returned is the modulus.
+ * For DSA the bits returned are of the public exponent.
+ *
+ * Unknown/unsupported algorithms are mapped to %GNUTLS_PK_UNKNOWN.
+ *
+ * Returns: a member of the #gnutls_pk_algorithm_t enumeration on
+ * success, or a negative error code on error.
+ *
+ * Since: 3.6.0
+ **/
+int
+gnutls_x509_crt_get_pk_algorithm2(gnutls_x509_crt_t cert,
+ gnutls_x509_spki_t spki,
+ unsigned int *bits)
+{
int result;
if (cert == NULL) {
@@ -1568,8 +1599,24 @@ gnutls_x509_crt_get_pk_algorithm(gnutls_x509_crt_t cert,
return result;
}
- return result;
+ if (spki) {
+ gnutls_x509_spki_st params;
+ spki->pk = result;
+
+ result = _gnutls_x509_crt_read_sign_params(cert, &params);
+ if (result < 0) {
+ gnutls_assert();
+ return result;
+ }
+
+ spki->dig = params.dig;
+ spki->salt_size = params.salt_size;
+
+ return spki->pk;
+ }
+
+ return result;
}
/* returns the type and the name on success.
@@ -4255,3 +4302,4 @@ void gnutls_x509_crt_set_flags(gnutls_x509_crt_t cert,
{
cert->flags = flags;
}
+
diff --git a/lib/x509/x509_int.h b/lib/x509/x509_int.h
index 38f07d6ed8..7b2d38457d 100644
--- a/lib/x509/x509_int.h
+++ b/lib/x509/x509_int.h
@@ -156,8 +156,12 @@ int _gnutls_x509_get_tbs(ASN1_TYPE cert, const char *tbs_name,
gnutls_datum_t * tbs);
int _gnutls_x509_pkix_sign(ASN1_TYPE src, const char *src_name,
gnutls_digest_algorithm_t,
+ unsigned int flags,
gnutls_x509_crt_t issuer,
gnutls_privkey_t issuer_key);
+int _gnutls_x509_crt_get_sign_params(gnutls_x509_crt_t issuer,
+ const gnutls_x509_spki_st *key_params,
+ gnutls_x509_spki_st *params);
/* dn.c */
#define OID_X520_COUNTRY_NAME "2.5.4.6"
@@ -229,11 +233,6 @@ _gnutls_x509_verify_algorithm(gnutls_digest_algorithm_t * hash,
gnutls_pk_algorithm_t pk,
gnutls_pk_params_st * issuer_params);
-int _gnutls_x509_verify_data(const mac_entry_st * me,
- const gnutls_datum_t * data,
- const gnutls_datum_t * signature,
- gnutls_x509_crt_t issuer);
-
/* privkey.h */
void _gnutls_x509_privkey_reinit(gnutls_x509_privkey_t key);
@@ -252,6 +251,19 @@ _gnutls_x509_read_ecc_params(uint8_t * der, int dersize,
int _gnutls_asn1_encode_privkey(gnutls_pk_algorithm_t pk, ASN1_TYPE * c2,
gnutls_pk_params_st * params, unsigned compat);
+int _gnutls_x509_privkey_get_sign_params(gnutls_x509_privkey_t key,
+ gnutls_x509_spki_st * params);
+int _gnutls_x509_privkey_find_sign_params(gnutls_x509_privkey_t key,
+ gnutls_pk_algorithm_t pk,
+ gnutls_digest_algorithm_t dig,
+ unsigned flags,
+ gnutls_x509_spki_st *params);
+
+int _gnutls_x509_read_rsa_pss_params(uint8_t * der, int dersize,
+ gnutls_x509_spki_st * params);
+int _gnutls_x509_write_rsa_pss_params(gnutls_x509_spki_st * params,
+ gnutls_datum_t * der);
+
/* extensions.c */
int _gnutls_x509_crl_get_extension_oid(gnutls_x509_crl_t crl,
int indx, void *oid,
@@ -312,13 +324,24 @@ int _gnutls_x509_crq_get_mpis(gnutls_x509_crq_t cert,
int _gnutls_x509_crt_get_mpis(gnutls_x509_crt_t cert,
gnutls_pk_params_st * params);
+int _gnutls_x509_crt_read_sign_params(gnutls_x509_crt_t crt,
+ gnutls_x509_spki_st *params);
+int _gnutls_x509_crq_read_sign_params(gnutls_x509_crq_t crt,
+ gnutls_x509_spki_st *params);
+
int _gnutls_x509_read_pubkey_params(gnutls_pk_algorithm_t, uint8_t * der,
int dersize,
gnutls_pk_params_st * params);
+int _gnutls_x509_check_pubkey_params(gnutls_pk_algorithm_t algo,
+ gnutls_pk_params_st * params);
int _gnutls_x509_read_pubkey(gnutls_pk_algorithm_t, uint8_t * der,
int dersize, gnutls_pk_params_st * params);
+int _gnutls_x509_read_pubkey_signature_params(gnutls_pk_algorithm_t algo,
+ uint8_t * der, int dersize,
+ gnutls_pk_params_st * params);
+
int _gnutls_x509_write_ecc_params(gnutls_ecc_curve_t curve,
gnutls_datum_t * der);
int _gnutls_x509_write_ecc_pubkey(gnutls_pk_params_st * params,
@@ -352,9 +375,10 @@ int _gnutls_x509_read_key_int(ASN1_TYPE node, const char *value,
int _gnutls_x509_write_key_int(ASN1_TYPE node, const char *value, bigint_t mpi,
int lz);
-int _gnutls_x509_write_sig_params(ASN1_TYPE dst, const char *dst_name,
- gnutls_pk_algorithm_t pk_algorithm,
- gnutls_digest_algorithm_t, unsigned legacy);
+int _gnutls_x509_read_sign_params(ASN1_TYPE src, const char *src_name,
+ gnutls_x509_spki_st *params);
+int _gnutls_x509_write_sign_params(ASN1_TYPE dst, const char *dst_name,
+ gnutls_x509_spki_st *params);
/* pkcs12.h */
#include <gnutls/pkcs12.h>
diff --git a/lib/x509/x509_write.c b/lib/x509/x509_write.c
index 70e9cc0b1d..da12905c71 100644
--- a/lib/x509/x509_write.c
+++ b/lib/x509/x509_write.c
@@ -35,6 +35,7 @@
#include <x509_b64.h>
#include "x509_int.h"
#include <libtasn1.h>
+#include <pk.h>
static void disable_optional_stuff(gnutls_x509_crt_t cert);
@@ -1815,7 +1816,7 @@ gnutls_x509_crt_privkey_sign(gnutls_x509_crt_t crt,
}
result = _gnutls_x509_pkix_sign(crt->cert, "tbsCertificate",
- dig, issuer, issuer_key);
+ dig, flags, issuer, issuer_key);
if (result < 0) {
gnutls_assert();
return result;
@@ -1989,3 +1990,102 @@ gnutls_x509_crt_set_policy(gnutls_x509_crt_t crt,
return ret;
}
+/**
+ * gnutls_x509_crt_set_pk_algorithm:
+ * @crt: a certificate of type #gnutls_x509_crt_t
+ * @spki: a SubjectPublicKeyInfo structure of type #gnutls_x509_spki_t
+ * @flags: must be zero
+ *
+ * This function will set the certificate's subject public key
+ * information explicitly. This is intended to be used in the cases
+ * where a single public key (e.g., RSA) can be used for multiple
+ * signature algorithms (RSA PKCS1-1.5, and RSA-PSS).
+ *
+ * To export the public key (i.e., the SubjectPublicKeyInfo part), check
+ * gnutls_pubkey_import_x509().
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
+ * negative error value.
+ *
+ * Since: 3.6.0
+ **/
+int
+gnutls_x509_crt_set_pk_algorithm(gnutls_x509_crt_t crt,
+ gnutls_x509_spki_t spki,
+ unsigned int flags)
+{
+ int result;
+ gnutls_pk_algorithm_t crt_pk;
+ gnutls_x509_spki_st params;
+ unsigned bits;
+
+ if (crt == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ result = gnutls_x509_crt_get_pk_algorithm(crt, &bits);
+ if (result < 0) {
+ gnutls_assert();
+ return result;
+ }
+
+ crt_pk = result;
+
+ if (spki->pk != GNUTLS_PK_RSA_PSS) {
+ if (crt_pk == spki->pk)
+ return 0;
+
+ gnutls_assert();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ if (crt_pk == GNUTLS_PK_RSA) {
+ const mac_entry_st *me;
+
+ me = hash_to_entry(spki->dig);
+ if (unlikely(me == NULL)) {
+ gnutls_assert();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ memset(&params, 0, sizeof(gnutls_x509_spki_st));
+ params.pk = spki->pk;
+ params.dig = spki->dig;
+
+ /* If salt size is zero, find the optimal salt size. */
+ if (spki->salt_size == 0) {
+ params.salt_size =
+ _gnutls_find_rsa_pss_salt_size(bits, me,
+ spki->salt_size);
+ } else
+ params.salt_size = spki->salt_size;
+ } else if (crt_pk == GNUTLS_PK_RSA_PSS) {
+ result = _gnutls_x509_crt_read_sign_params(crt, &params);
+ if (result < 0) {
+ gnutls_assert();
+ return result;
+ }
+
+ if (params.dig != spki->dig ||
+ params.salt_size > spki->salt_size) {
+ gnutls_assert();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ params.salt_size = spki->salt_size;
+ }
+
+ MODIFIED(crt);
+
+ result = _gnutls_x509_write_sign_params(crt->cert,
+ "tbsCertificate."
+ "subjectPublicKeyInfo.algorithm",
+ &params);
+ if (result < 0) {
+ gnutls_assert();
+ return result;
+ }
+
+ return 0;
+}