From d3ee878e02d9804787179993de513d27b3e53f80 Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Mon, 15 Apr 2019 14:32:55 +0200 Subject: certtool: generate RSA-PSS certificates from RSA keys When generating certificates it was not possible to generate an RSA-PSS certificate from an RSA key (common scenario). This fixes the certificate generation to include such a method. Ironically there was a test for this scenario but the test was limited to checking that the combination of certtool parameters succeeded; modified the test to check the textual expression of the certificate for the RSA-PSS indicators. Signed-off-by: Nikos Mavrogiannopoulos --- src/certtool-args.def | 4 ++- src/certtool.c | 52 ++++++++++++++++++++++++++++----------- tests/cert-tests/certtool-rsa-pss | 33 ++++++++++++++++++++++++- tests/cert-tests/rsa-pss-pad | 4 +-- 4 files changed, 74 insertions(+), 19 deletions(-) diff --git a/src/certtool-args.def b/src/certtool-args.def index 27ca2c8ed4..35741a21c8 100644 --- a/src/certtool-args.def +++ b/src/certtool-args.def @@ -200,7 +200,9 @@ flag = { arg-type = string; descrip = "Specify the key type to use on key generation"; doc = "This option can be combined with --generate-privkey, to specify -the key type to be generated. Valid options are, 'rsa', 'rsa-pss', 'dsa', 'ecdsa', and 'ed25519'."; +the key type to be generated. Valid options are, 'rsa', 'rsa-pss', 'dsa', 'ecdsa', and 'ed25519'. +When combined with certificate generation it can be used to specify an +RSA-PSS certificate when an RSA key is given."; }; flag = { diff --git a/src/certtool.c b/src/certtool.c index 11dc27a6fd..4d2b7c6a98 100644 --- a/src/certtool.c +++ b/src/certtool.c @@ -128,6 +128,21 @@ int main(int argc, char **argv) return 0; } +#define SET_SPKI_PARAMS(spki, cinfo) \ + do { \ + unsigned _salt_size; \ + if (!cinfo->hash) { \ + fprintf(stderr, "You must provide the hash algorithm and optionally the salt size for RSA-PSS\n"); \ + app_exit(1); \ + } \ + if (HAVE_OPT(SALT_SIZE)) { \ + _salt_size = OPT_VALUE_SALT_SIZE; \ + } else { \ + _salt_size = gnutls_hash_get_len(cinfo->hash); \ + } \ + gnutls_x509_spki_set_rsa_pss_params(spki, cinfo->hash, _salt_size); \ + } while(0) + static gnutls_x509_privkey_t generate_private_key_int(common_info_st * cinfo) { @@ -220,20 +235,8 @@ generate_private_key_int(common_info_st * cinfo) } if (key_type == GNUTLS_PK_RSA_PSS && (cinfo->hash || HAVE_OPT(SALT_SIZE))) { - unsigned salt_size; - - if (!cinfo->hash) { - fprintf(stderr, "You must provide the hash algorithm and optionally the salt size for RSA-PSS\n"); - app_exit(1); - } - - if (HAVE_OPT(SALT_SIZE)) { - salt_size = OPT_VALUE_SALT_SIZE; - } else { - salt_size = gnutls_hash_get_len(cinfo->hash); - } - gnutls_x509_spki_set_rsa_pss_params(spki, cinfo->hash, salt_size); + SET_SPKI_PARAMS(spki, cinfo); kdata[kdata_size].type = GNUTLS_KEYGEN_SPKI; kdata[kdata_size].data = (void*)spki; @@ -308,6 +311,7 @@ generate_certificate(gnutls_privkey_t * ret_key, common_info_st * cinfo) { gnutls_x509_crt_t crt; + gnutls_x509_spki_t spki; gnutls_privkey_t key = NULL; gnutls_pubkey_t pubkey; size_t size; @@ -715,11 +719,10 @@ generate_certificate(gnutls_privkey_t * ret_key, app_exit(1); } + /* Set algorithm parameter restriction in CAs. */ if (pk == GNUTLS_PK_RSA_PSS && ca_status && key) { - gnutls_x509_spki_t spki; - result = gnutls_x509_spki_init(&spki); if (result < 0) { fprintf(stderr, "spki_init: %s\n", @@ -737,6 +740,25 @@ generate_certificate(gnutls_privkey_t * ret_key, } } + gnutls_x509_spki_deinit(spki); + + } else if (pk == GNUTLS_PK_RSA && req_key_type == GNUTLS_PK_RSA_PSS) { + result = gnutls_x509_spki_init(&spki); + if (result < 0) { + fprintf(stderr, "spki_init: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + + SET_SPKI_PARAMS(spki, cinfo); + + result = gnutls_x509_crt_set_spki(crt, spki, 0); + if (result < 0) { + fprintf(stderr, "error setting RSA-PSS SPKI information: %s\n", + gnutls_strerror(result)); + app_exit(1); + } + gnutls_x509_spki_deinit(spki); } diff --git a/tests/cert-tests/certtool-rsa-pss b/tests/cert-tests/certtool-rsa-pss index f8126a5523..baa819c6ac 100755 --- a/tests/cert-tests/certtool-rsa-pss +++ b/tests/cert-tests/certtool-rsa-pss @@ -49,7 +49,7 @@ if test "${rc}" != "0"; then exit 1 fi -${VALGRIND} "${CERTTOOL}" -k --password '' --infile "$OUTFILE" +${VALGRIND} "${CERTTOOL}" -k --password '' --infile "$OUTFILE" >/dev/null rc=$? if test "${rc}" != "0"; then echo "Could not read generated an RSA-PSS key ($i)" @@ -68,6 +68,8 @@ if test "${rc}" != "0"; then exit 1 fi +rm -f "${TMPFILE}" + # Create an RSA-PSS certificate from an RSA-PSS private key, with # mismatched parameters for j in sha256 sha384 sha512;do @@ -82,6 +84,7 @@ if test "$j" != "$j" && "${rc}" = "0"; then exit 1 fi done +rm -f "${TMPFILE}" # Create an RSA-PSS certificate from an RSA key ${VALGRIND} "${CERTTOOL}" --generate-certificate --key-type rsa-pss \ @@ -97,6 +100,15 @@ if test "${rc}" != "0"; then exit 1 fi +${CERTTOOL} -i --infile ${TMPFILE}|grep -i "Subject Public Key Algorithm: RSA-PSS" +if test $? != 0;then + echo "Generated certificate is not RSA-PSS" + cat ${TMPFILE} + exit 1 +fi + +rm -f "${TMPFILE}" + # Create an RSA certificate from an RSA key, and sign it with RSA-PSS ${VALGRIND} "${CERTTOOL}" --generate-certificate --rsa --sign-params rsa-pss \ --load-privkey "${srcdir}/../../doc/credentials/x509/key-rsa.pem" \ @@ -110,6 +122,23 @@ if test "${rc}" != "0"; then echo "Could not generate an RSA-PSS certificate" exit 1 fi + +${CERTTOOL} -i --infile ${TMPFILE}|tr -d '\r'|grep -i 'Subject Public Key Algorithm: RSA$' >/dev/null +if test $? != 0;then + echo "Generated certificate is not RSA" + cat ${TMPFILE} + exit 1 +fi + +${CERTTOOL} -i --infile ${TMPFILE}|grep -i "Signature Algorithm: RSA-PSS" +if test $? != 0;then + echo "Generated certificate is not signed with RSA-PSS" + cat ${TMPFILE} + exit 1 +fi + +rm -f "${TMPFILE}" + done # Convert an RSA-PSS key to an RSA key @@ -133,6 +162,8 @@ fi echo "RSA-PSS to RSA conversion was successful" +rm -f "${TMPFILE}" + export TZ="UTC" . ${srcdir}/../scripts/common.sh diff --git a/tests/cert-tests/rsa-pss-pad b/tests/cert-tests/rsa-pss-pad index e2eccfbe8e..d9a05e4e0f 100755 --- a/tests/cert-tests/rsa-pss-pad +++ b/tests/cert-tests/rsa-pss-pad @@ -44,9 +44,9 @@ check_for_datefudge for i in sha256 sha384 sha512;do datefudge -s "2007-04-22" \ "${CERTTOOL}" --generate-self-signed --key-type rsa-pss \ - --load-privkey "${srcdir}/data/template-test.key" \ + --load-privkey "${srcdir}/data/privkey1.pem" \ --template "${srcdir}/templates/template-test.tmpl" \ - --outfile "${TMPFILE}" --hash $i 2>/dev/null + --outfile "${TMPFILE}" --hash $i rc=$? if test -f "${srcdir}/data/template-rsa-$i.pem";then -- cgit v1.2.1 From 86640a54f758f24fd13c83ec2c64a3270e461794 Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Sat, 20 Apr 2019 18:46:23 +0200 Subject: certtool: refuse to accept an incompatible key type Signed-off-by: Nikos Mavrogiannopoulos --- src/certtool.c | 15 +++++++++++++-- tests/cert-tests/certtool-rsa-pss | 36 ++++++++++++++++++++++++++++++------ 2 files changed, 43 insertions(+), 8 deletions(-) diff --git a/src/certtool.c b/src/certtool.c index 4d2b7c6a98..6623b86385 100644 --- a/src/certtool.c +++ b/src/certtool.c @@ -92,9 +92,11 @@ static gnutls_digest_algorithm_t get_dig(gnutls_x509_crt_t crt, common_info_st * FILE *outfile; static const char *outfile_name = NULL; /* to delete on exit */ +#define REQ_KEY_TYPE_DEFAULT GNUTLS_PK_RSA + FILE *infile; static unsigned int incert_format, outcert_format; -static unsigned int req_key_type = GNUTLS_PK_RSA; +static unsigned int req_key_type = REQ_KEY_TYPE_DEFAULT; gnutls_certificate_print_formats_t full_format = GNUTLS_CRT_PRINT_FULL; /* non interactive operation if set @@ -719,6 +721,13 @@ generate_certificate(gnutls_privkey_t * ret_key, app_exit(1); } + if ((HAVE_OPT(KEY_TYPE) || req_key_type != REQ_KEY_TYPE_DEFAULT) && req_key_type != pk) { + if (pk != GNUTLS_PK_RSA || req_key_type != GNUTLS_PK_RSA_PSS) { + fprintf(stderr, "cannot set certificate type (%s) incompatible with the key (%s)\n", + gnutls_pk_get_name(req_key_type), gnutls_pk_get_name(pk)); + app_exit(1); + } + } /* Set algorithm parameter restriction in CAs. */ @@ -1257,7 +1266,9 @@ static void cmd_parser(int argc, char **argv) outcert_format = GNUTLS_X509_FMT_PEM; /* legacy options */ - if (HAVE_OPT(DSA)) { + if (HAVE_OPT(RSA)) { + req_key_type = GNUTLS_PK_RSA; + } else if (HAVE_OPT(DSA)) { req_key_type = GNUTLS_PK_DSA; } else if (HAVE_OPT(ECC)) { req_key_type = GNUTLS_PK_ECDSA; diff --git a/tests/cert-tests/certtool-rsa-pss b/tests/cert-tests/certtool-rsa-pss index baa819c6ac..617591377d 100755 --- a/tests/cert-tests/certtool-rsa-pss +++ b/tests/cert-tests/certtool-rsa-pss @@ -25,6 +25,7 @@ CERTTOOL="${CERTTOOL:-../../src/certtool${EXEEXT}}" DIFF="${DIFF:-diff -b -B}" OUTFILE=cert-pss-privkey.$$.tmp TMPFILE=cert-pss.$$.tmp +TMPFILE2=cert2-pss.$$.tmp if ! test -x "${CERTTOOL}"; then exit 77 @@ -60,7 +61,7 @@ fi ${VALGRIND} "${CERTTOOL}" --generate-self-signed \ --pkcs8 --load-privkey "$OUTFILE" --password '' \ --template "${srcdir}/templates/template-test.tmpl" \ - --outfile "${TMPFILE}" --hash $i 2>/dev/null + --outfile "${TMPFILE}" --hash $i rc=$? if test "${rc}" != "0"; then @@ -76,7 +77,7 @@ for j in sha256 sha384 sha512;do ${VALGRIND} "${CERTTOOL}" --generate-self-signed \ --pkcs8 --load-privkey "$OUTFILE" --password '' \ --template "${srcdir}/templates/template-test.tmpl" \ - --outfile "${TMPFILE}" --hash $j 2>/dev/null + --outfile "${TMPFILE}" --hash $j rc=$? if test "$j" != "$j" && "${rc}" = "0"; then @@ -92,7 +93,7 @@ ${VALGRIND} "${CERTTOOL}" --generate-certificate --key-type rsa-pss \ --load-ca-privkey "${srcdir}/../../doc/credentials/x509/ca-key.pem" \ --load-ca-certificate "${srcdir}/../../doc/credentials/x509/ca.pem" \ --template "${srcdir}/templates/template-test.tmpl" \ - --outfile "${TMPFILE}" --hash $i 2>/dev/null + --outfile "${TMPFILE}" --hash $i rc=$? if test "${rc}" != "0"; then @@ -109,13 +110,27 @@ fi rm -f "${TMPFILE}" +# Create an RSA certificate from an RSA key, with wrong key-type, should fail +${VALGRIND} "${CERTTOOL}" --generate-certificate --key-type ecdsa \ + --load-privkey "${srcdir}/../../doc/credentials/x509/key-rsa.pem" \ + --load-ca-privkey "${srcdir}/../../doc/credentials/x509/ca-key.pem" \ + --load-ca-certificate "${srcdir}/../../doc/credentials/x509/ca.pem" \ + --template "${srcdir}/templates/template-test.tmpl" \ + --outfile "${TMPFILE}" +rc=$? + +if test "${rc}" = "0"; then + echo "Succeeded with wrong key type" + exit 1 +fi + # Create an RSA certificate from an RSA key, and sign it with RSA-PSS ${VALGRIND} "${CERTTOOL}" --generate-certificate --rsa --sign-params rsa-pss \ --load-privkey "${srcdir}/../../doc/credentials/x509/key-rsa.pem" \ --load-ca-privkey "${srcdir}/../../doc/credentials/x509/ca-key.pem" \ --load-ca-certificate "${srcdir}/../../doc/credentials/x509/ca.pem" \ --template "${srcdir}/templates/template-test.tmpl" \ - --outfile "${TMPFILE}" --hash $i 2>/dev/null + --outfile "${TMPFILE}" --hash $i rc=$? if test "${rc}" != "0"; then @@ -123,21 +138,30 @@ if test "${rc}" != "0"; then exit 1 fi -${CERTTOOL} -i --infile ${TMPFILE}|tr -d '\r'|grep -i 'Subject Public Key Algorithm: RSA$' >/dev/null +${CERTTOOL} -i --infile ${TMPFILE}|tr -d '\r' > ${TMPFILE2} +grep -i 'Subject Public Key Algorithm: RSA$' ${TMPFILE2} >/dev/null if test $? != 0;then echo "Generated certificate is not RSA" cat ${TMPFILE} exit 1 fi -${CERTTOOL} -i --infile ${TMPFILE}|grep -i "Signature Algorithm: RSA-PSS" +grep -i "Signature Algorithm: RSA-PSS" ${TMPFILE2} if test $? != 0;then echo "Generated certificate is not signed with RSA-PSS" cat ${TMPFILE} exit 1 fi +grep -i "Signature Algorithm: RSA-PSS-${i}" ${TMPFILE2} +if test $? != 0;then + echo "Generated certificate is not signed with RSA-PSS-${i}" + cat ${TMPFILE} + exit 1 +fi + rm -f "${TMPFILE}" +rm -f "${TMPFILE2}" done -- cgit v1.2.1