summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorDaiki Ueno <dueno@redhat.com>2017-03-16 11:38:58 +0100
committerNikos Mavrogiannopoulos <nmav@redhat.com>2017-05-29 08:23:49 +0200
commit9e5452193c3510102801fd86b6e65d37b5dc1012 (patch)
tree1c401b3900c8a6f3ffac58ad839266e8c228f941 /lib
parent03c811b7f9a280182b486473567a0b93fe1dc291 (diff)
downloadgnutls-9e5452193c3510102801fd86b6e65d37b5dc1012.tar.gz
x509: implement RSA-PSS signature scheme
This patch enables RSA-PSS signature scheme in the X.509 functions and certtool. When creating RSA-PSS signature, there are 3 different scenarios: a. both a private key and a certificate are RSA-PSS b. the private key is RSA, while the certificate is RSA-PSS c. both the private key and the certificate are RSA For (a) and (b), the RSA-PSS parameters are read from the certificate. Any conflicts in parameters between the private key and the certificate are reported as an error. For (c), the sign functions, such as gnutls_x509_crt_privkey_sign() or gnutls_privkey_sign_data(), shall be instructed to generate an RSA-PSS signature. This can be done with the new flag GNUTLS_PRIVKEY_SIGN_FLAG_RSA_PSS. Verification is similar to signing, except for the case (c), use the flag GNUTLS_VERIFY_USE_RSA_PSS instead of GNUTLS_PRIVKEY_SIGN_FLAG_RSA_PSS. From the command line, certtool has a couple of new options: --rsa-pss and --rsa-pss-sign. The --rsa-pss option indicates that the generated private key or certificate is restricted to RSA-PSS, while the --rsa-pss-sign option indicates that the generated certificate is signed with RSA-PSS. For simplicity, there is no means of choosing arbitrary salt length. When it is not given by a private key or a certificate, it is automatically calculated from the underlying hash algorithm and the RSA modulus bits. [minor naming changes by nmav] Signed-off-by: Daiki Ueno <dueno@redhat.com> Signed-off-by: Nikos Mavrogiannopoulos <nmav@redhat.com>
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;
+}