Enable RSA-PSS signatures in pkcs11-tool (#1146)

* Add missing SHA224 RSA algorithms

* Fix wrong replacement in pkcs11-tool manual page

* Add MGF and PSS_PARAMS definitions in PKCS#11 header file

* Inspect PSS signature parameters in pkcs11-spy

* Enable RSA-PSS signatures in pkcs11-tool

* Added short names to RSA-PSS methods

* Reintroduce portable NORETURN indication for functions and use it to avoid compilers complaining
This commit is contained in:
Jakub Jelen 2017-09-21 11:19:22 +02:00 committed by Frank Morgner
parent 8965ee38dd
commit bdb1961dee
8 changed files with 280 additions and 9 deletions

View File

@ -71,6 +71,14 @@
<listitem><para>Hash some data.</para></listitem>
</varlistentry>
<varlistentry>
<term>
<option>--hash-algorithm</option> <replaceable>mechanism</replaceable>
</term>
<listitem><para>Specify hash algorithm used with
RSA-PKCS-PSS signature. Default is SHA-1.</para></listitem>
</varlistentry>
<varlistentry>
<term>
<option>--id</option> <replaceable>id</replaceable>,
@ -116,7 +124,7 @@
<varlistentry>
<term>
<option>--key-type</option> <replacement>specification</replacement>
<option>--key-type</option> <replaceable>specification</replaceable>
</term>
<listitem><para>Specify the type and length of the key to create, for example rsa:1024 or EC:prime256v1.</para></listitem>
</varlistentry>
@ -212,6 +220,17 @@
of mechanisms supported by your token.</para></listitem>
</varlistentry>
<varlistentry>
<term>
<option>--mgf</option> <replaceable>function</replaceable>
</term>
<listitem><para>Use the specified Message Generation
Function (MGF) <replaceable>function</replaceable>
for RSA-PSS signatures. Supported arguments are MGF1-SHA1
to MGF1-SHA512 if supported by the driver.
The default is based on the hash selection.</para></listitem>
</varlistentry>
<varlistentry>
<term>
<option>--module</option> <replaceable>mod</replaceable>
@ -309,6 +328,17 @@
<listitem><para>Derive a secret key using another key and some data.</para></listitem>
</varlistentry>
<varlistentry>
<term>
<option>--salt-len</option> <replaceable>bytes</replaceable>
</term>
<listitem><para>Specify how many bytes of salt should
be used in RSA-PSS signatures. Accepts two special values:
"-1" means salt length equals to digest length,
"-2" means use maximum permissible length.
Default is digest length (-1).</para></listitem>
</varlistentry>
<varlistentry>
<term>
<option>--slot</option> <replaceable>id</replaceable>

View File

@ -521,6 +521,14 @@ static enum_specs ck_mec_s[] = {
{ CKM_VENDOR_DEFINED , "CKM_VENDOR_DEFINED " }
};
static enum_specs ck_mgf_s[] = {
{ CKG_MGF1_SHA1 , "CKG_MGF1_SHA1 " },
{ CKG_MGF1_SHA224, "CKG_MGF1_SHA224" },
{ CKG_MGF1_SHA256, "CKG_MGF1_SHA256" },
{ CKG_MGF1_SHA384, "CKG_MGF1_SHA384" },
{ CKG_MGF1_SHA512, "CKG_MGF1_SHA512" },
};
static enum_specs ck_err_s[] = {
{ CKR_OK, "CKR_OK" },
{ CKR_CANCEL, "CKR_CANCEL" },
@ -630,6 +638,7 @@ enum_spec ck_types[] = {
{ KEY_T, ck_key_s, sizeof(ck_key_s) / SZ_SPECS, "CK_KEY_TYPE" },
{ CRT_T, ck_crt_s, sizeof(ck_crt_s) / SZ_SPECS, "CK_CERTIFICATE_TYPE" },
{ MEC_T, ck_mec_s, sizeof(ck_mec_s) / SZ_SPECS, "CK_MECHANISM_TYPE" },
{ MGF_T, ck_mgf_s, sizeof(ck_mgf_s) / SZ_SPECS, "CK_RSA_PKCS_MGF_TYPE"},
{ USR_T, ck_usr_s, sizeof(ck_usr_s) / SZ_SPECS, "CK_USER_TYPE" },
{ STA_T, ck_sta_s, sizeof(ck_sta_s) / SZ_SPECS, "CK_STATE" },
{ RV_T, ck_err_s, sizeof(ck_err_s) / SZ_SPECS, "CK_RV" },

View File

@ -56,6 +56,7 @@ enum ck_type{
KEY_T,
CRT_T,
MEC_T,
MGF_T,
USR_T,
STA_T,
RV_T

View File

@ -969,6 +969,24 @@ C_SignInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HA
enter("C_SignInit");
spy_dump_ulong_in("hSession", hSession);
fprintf(spy_output, "pMechanism->type=%s\n", lookup_enum(MEC_T, pMechanism->mechanism));
switch (pMechanism->mechanism) {
case CKM_RSA_PKCS_PSS:
case CKM_SHA1_RSA_PKCS_PSS:
case CKM_SHA256_RSA_PKCS_PSS:
case CKM_SHA384_RSA_PKCS_PSS:
case CKM_SHA512_RSA_PKCS_PSS:
if (pMechanism->pParameter != NULL) {
CK_RSA_PKCS_PSS_PARAMS *param =
(CK_RSA_PKCS_PSS_PARAMS *) pMechanism->pParameter;
fprintf(spy_output, "pMechanism->pParameter->hashAlg=%s\n",
lookup_enum(MEC_T, param->hashAlg));
fprintf(spy_output, "pMechanism->pParameter->mgf=%s\n",
lookup_enum(MGF_T, param->mgf));
fprintf(spy_output, "pMechanism->pParameter->sLen=%lu\n",
param->sLen);
}
break;
}
spy_dump_ulong_in("hKey", hKey);
rv = po->C_SignInit(hSession, pMechanism, hKey);
return retne(rv);

View File

@ -153,6 +153,8 @@ extern "C" {
#define ck_mechanism_type_t CK_MECHANISM_TYPE
#define ck_rsa_pkcs_mgf_type_t CK_RSA_PKCS_MGF_TYPE
#define ck_mechanism _CK_MECHANISM
#define parameter pParameter
#define parameter_len ulParameterLen
@ -478,6 +480,8 @@ struct ck_date
typedef unsigned long ck_mechanism_type_t;
typedef unsigned long int ck_rsa_pkcs_mgf_type_t;
#define CKM_RSA_PKCS_KEY_PAIR_GEN (0UL)
#define CKM_RSA_PKCS (1UL)
#define CKM_RSA_9796 (2UL)
@ -508,6 +512,8 @@ typedef unsigned long ck_mechanism_type_t;
#define CKM_SHA256_RSA_PKCS_PSS (0x43UL)
#define CKM_SHA384_RSA_PKCS_PSS (0x44UL)
#define CKM_SHA512_RSA_PKCS_PSS (0x45UL)
#define CKM_SHA224_RSA_PKCS (0x46UL)
#define CKM_SHA224_RSA_PKCS_PSS (0x47UL)
#define CKM_RC2_KEY_GEN (0x100UL)
#define CKM_RC2_ECB (0x101UL)
#define CKM_RC2_CBC (0x102UL)
@ -553,6 +559,9 @@ typedef unsigned long ck_mechanism_type_t;
#define CKM_SHA256 (0x250UL)
#define CKM_SHA256_HMAC (0x251UL)
#define CKM_SHA256_HMAC_GENERAL (0x252UL)
#define CKM_SHA224 (0x255UL)
#define CKM_SHA224_HMAC (0x256UL)
#define CKM_SHA224_HMAC_GENERAL (0x257UL)
#define CKM_SHA384 (0x260UL)
#define CKM_SHA384_HMAC (0x261UL)
#define CKM_SHA384_HMAC_GENERAL (0x262UL)
@ -755,6 +764,17 @@ typedef struct CK_ECDH1_DERIVE_PARAMS {
unsigned char * pPublicData;
} CK_ECDH1_DERIVE_PARAMS;
typedef struct CK_RSA_PKCS_PSS_PARAMS {
ck_mechanism_type_t hashAlg;
unsigned long mgf;
unsigned long sLen;
} CK_RSA_PKCS_PSS_PARAMS;
#define CKG_MGF1_SHA1 (0x00000001UL)
#define CKG_MGF1_SHA224 (0x00000005UL)
#define CKG_MGF1_SHA256 (0x00000002UL)
#define CKG_MGF1_SHA384 (0x00000003UL)
#define CKG_MGF1_SHA512 (0x00000004UL)
typedef unsigned long ck_rv_t;
@ -1292,6 +1312,8 @@ typedef struct ck_date *CK_DATE_PTR;
typedef ck_mechanism_type_t *CK_MECHANISM_TYPE_PTR;
typedef ck_rsa_pkcs_mgf_type_t *CK_RSA_PKCS_MGF_TYPE_PTR;
typedef struct ck_mechanism CK_MECHANISM;
typedef struct ck_mechanism *CK_MECHANISM_PTR;
@ -1362,6 +1384,8 @@ typedef struct ck_c_initialize_args *CK_C_INITIALIZE_ARGS_PTR;
#undef ck_mechanism_type_t
#undef ck_rsa_pkcs_mgf_type_t
#undef ck_mechanism
#undef parameter
#undef parameter_len

View File

@ -147,6 +147,9 @@ enum {
OPT_TEST_FORK,
OPT_GENERATE_KEY,
OPT_GENERATE_RANDOM,
OPT_HASH_ALGORITHM,
OPT_MGF,
OPT_SALT,
};
static const struct option options[] = {
@ -163,6 +166,9 @@ static const struct option options[] = {
{ "derive", 0, NULL, OPT_DERIVE },
{ "derive-pass-der", 0, NULL, OPT_DERIVE_PASS_DER },
{ "mechanism", 1, NULL, 'm' },
{ "hash-algorithm", 1, NULL, OPT_HASH_ALGORITHM },
{ "mgf", 1, NULL, OPT_MGF },
{ "salt-len", 1, NULL, OPT_SALT },
{ "login", 0, NULL, 'l' },
{ "login-type", 1, NULL, OPT_LOGIN_TYPE },
@ -229,6 +235,9 @@ static const char *option_help[] = {
"Derive a secret key using another key and some data",
"Derive ECDHpass DER encoded pubkey for compatibility with some PKCS#11 implementations",
"Specify mechanism (use -M for a list of supported mechanisms)",
"Specify hash algorithm used with RSA-PKCS-PSS signature",
"Specify MGF (Message Generation Function) used for RSA-PSS signatures (possible values are MGF1-SHA1 to MGF1-SHA512)",
"Specify how many bytes should be used for salt in RSA-PSS signatures (default is digest size)",
"Log into the token first",
"Specify login type ('so', 'user', 'context-specific'; default:'user')",
@ -320,6 +329,10 @@ static int opt_key_usage_derive = 0;
static int opt_key_usage_default = 1; /* uses defaults if no opt_key_usage options */
static int opt_derive_pass_der = 0;
static unsigned long opt_random_bytes = 0;
static CK_MECHANISM_TYPE opt_hash_alg = 0;
static unsigned long opt_mgf = 0;
static long salt_len = 0;
static int salt_len_given = 0; /* 0 - not given, 1 - given with input parameters */
static void *module = NULL;
static CK_FUNCTION_LIST_PTR p11 = NULL;
@ -410,6 +423,8 @@ static const char * p11_utf8_to_local(CK_UTF8CHAR *, size_t);
static const char * p11_flag_names(struct flag_info *, CK_FLAGS);
static const char * p11_mechanism_to_name(CK_MECHANISM_TYPE);
static CK_MECHANISM_TYPE p11_name_to_mechanism(const char *);
static const char * p11_mgf_to_name(CK_RSA_PKCS_MGF_TYPE);
static CK_MECHANISM_TYPE p11_name_to_mgf(const char *);
static void p11_perror(const char *, CK_RV);
static const char * CKR2Str(CK_ULONG res);
static int p11_test(CK_SESSION_HANDLE session);
@ -677,6 +692,16 @@ int main(int argc, char * argv[])
opt_mechanism_used = 1;
opt_mechanism = p11_name_to_mechanism(optarg);
break;
case OPT_HASH_ALGORITHM:
opt_hash_alg = p11_name_to_mechanism(optarg);
break;
case OPT_MGF:
opt_mgf = p11_name_to_mgf(optarg);
break;
case OPT_SALT:
salt_len = (CK_ULONG) strtoul(optarg, NULL, 0);
salt_len_given = 1;
break;
case 'o':
opt_output = optarg;
break;
@ -1609,15 +1634,45 @@ static int unlock_pin(CK_SLOT_ID slot, CK_SESSION_HANDLE sess, int login_type)
return 0;
}
/* return digest length in bytes */
static unsigned long figure_pss_salt_length(const int hash) {
unsigned long sLen = 0;
switch (hash) {
case CKM_SHA_1:
sLen = 20;
break;
case CKM_SHA224:
sLen = 28;
break;
case CKM_SHA256:
sLen = 32;
break;
case CKM_SHA384:
sLen = 48;
break;
case CKM_SHA512:
sLen = 64;
break;
default:
util_fatal("Unknown hash algorithm '%s' for RSA-PSS signatures",
p11_mechanism_to_name(hash));
break;
}
return sLen;
}
static void sign_data(CK_SLOT_ID slot, CK_SESSION_HANDLE session,
CK_OBJECT_HANDLE key)
{
unsigned char in_buffer[1025], sig_buffer[512];
CK_MECHANISM mech;
CK_RSA_PKCS_PSS_PARAMS pss_params;
CK_RV rv;
CK_ULONG sig_len;
int fd, r;
unsigned long hashlen = 0, modlen = 0;
if (!opt_mechanism_used)
if (!find_mechanism(slot, CKF_SIGN|CKF_HW, NULL, 0, &opt_mechanism))
util_fatal("Sign mechanism not supported");
@ -1625,6 +1680,93 @@ static void sign_data(CK_SLOT_ID slot, CK_SESSION_HANDLE session,
fprintf(stderr, "Using signature algorithm %s\n", p11_mechanism_to_name(opt_mechanism));
memset(&mech, 0, sizeof(mech));
mech.mechanism = opt_mechanism;
pss_params.hashAlg = 0;
if (opt_hash_alg != 0 && opt_mechanism != CKM_RSA_PKCS_PSS)
util_fatal("The hash-algorithm is applicable only to "
"RSA-PKCS-PSS mechanism");
/* set "default" MGF and hash algorithms. We can overwrite MGF later */
switch (opt_mechanism) {
case CKM_RSA_PKCS_PSS:
pss_params.hashAlg = opt_hash_alg;
switch (opt_hash_alg) {
case CKM_SHA256:
pss_params.mgf = CKG_MGF1_SHA256;
break;
case CKM_SHA384:
pss_params.mgf = CKG_MGF1_SHA384;
break;
case CKM_SHA512:
pss_params.mgf = CKG_MGF1_SHA512;
break;
default:
/* the PSS should use SHA-1 if not specified */
pss_params.hashAlg = CKM_SHA_1;
/* fallthrough */
case CKM_SHA_1:
pss_params.mgf = CKG_MGF1_SHA1;
}
break;
case CKM_SHA1_RSA_PKCS_PSS:
pss_params.hashAlg = CKM_SHA_1;
pss_params.mgf = CKG_MGF1_SHA1;
break;
case CKM_SHA256_RSA_PKCS_PSS:
pss_params.hashAlg = CKM_SHA256;
pss_params.mgf = CKG_MGF1_SHA256;
break;
case CKM_SHA384_RSA_PKCS_PSS:
pss_params.hashAlg = CKM_SHA384;
pss_params.mgf = CKG_MGF1_SHA384;
break;
case CKM_SHA512_RSA_PKCS_PSS:
pss_params.hashAlg = CKM_SHA512;
pss_params.mgf = CKG_MGF1_SHA512;
break;
}
/* One of RSA-PSS mechanisms above: They need parameters */
if (pss_params.hashAlg) {
if (opt_mgf != 0)
pss_params.mgf = opt_mgf;
hashlen = figure_pss_salt_length(pss_params.hashAlg);
if (salt_len_given == 1) { /* salt size explicitly given */
if (salt_len < 0 && salt_len != -1 && salt_len != -2)
util_fatal("Salt length must be greater or equal \
to zero, or equal to -1 (meaning: use digest size) or to -2 \
(meaning: use maximum permissible size");
modlen = (get_private_key_length(session, key) + 7) / 8;
switch(salt_len) {
case -1: /* salt size equals to digest size */
pss_params.sLen = hashlen;
break;
case -2: /* maximum permissible salt len */
pss_params.sLen = modlen - hashlen -2;
break;
default: /* use given size but its value must be >= 0 */
pss_params.sLen = salt_len;
break;
} /* end switch (salt_len_given) */
} else { /* use default: salt len of digest size */
pss_params.sLen = hashlen;
}
mech.pParameter = &pss_params;
mech.ulParameterLen = sizeof(pss_params);
fprintf(stderr, "PSS parameters: hashAlg=%s, mgf=%s, salt=%lu B\n",
p11_mechanism_to_name(pss_params.hashAlg),
p11_mgf_to_name(pss_params.mgf),
pss_params.sLen);
}
if (opt_input == NULL)
fd = 0;
@ -5649,10 +5791,10 @@ static struct mech_info p11_mechanisms[] = {
{ CKM_RSA_X9_31, "RSA-X9-31", NULL },
{ CKM_SHA1_RSA_X9_31, "SHA1-RSA-X9-31", NULL },
{ CKM_RSA_PKCS_PSS, "RSA-PKCS-PSS", NULL },
{ CKM_SHA1_RSA_PKCS_PSS, "SHA1-RSA-PKCS-PSS", NULL },
{ CKM_SHA256_RSA_PKCS_PSS,"SHA256-RSA-PKCS-PSS", NULL },
{ CKM_SHA384_RSA_PKCS_PSS,"SHA384-RSA-PKCS-PSS", NULL },
{ CKM_SHA512_RSA_PKCS_PSS,"SHA512-RSA-PKCS-PSS", NULL },
{ CKM_SHA1_RSA_PKCS_PSS, "SHA1-RSA-PKCS-PSS", "rsa-pss-sha1" },
{ CKM_SHA256_RSA_PKCS_PSS,"SHA256-RSA-PKCS-PSS", "rsa-pss-sha256" },
{ CKM_SHA384_RSA_PKCS_PSS,"SHA384-RSA-PKCS-PSS", "rsa-pss-sha384" },
{ CKM_SHA512_RSA_PKCS_PSS,"SHA512-RSA-PKCS-PSS", "rsa-pss-sha512" },
{ CKM_DSA_KEY_PAIR_GEN, "DSA-KEY-PAIR-GEN", NULL },
{ CKM_DSA, "DSA", NULL },
{ CKM_DSA_SHA1, "DSA-SHA1", NULL },
@ -5829,6 +5971,15 @@ static struct mech_info p11_mechanisms[] = {
{ 0, NULL, NULL }
};
static struct mech_info p11_mgf[] = {
{ CKG_MGF1_SHA1, "MGF1-SHA1", NULL },
{ CKG_MGF1_SHA224, "MGF1-SHA224", NULL },
{ CKG_MGF1_SHA256, "MGF1-SHA256", NULL },
{ CKG_MGF1_SHA384, "MGF1-SHA384", NULL },
{ CKG_MGF1_SHA512, "MGF1-SHA512", NULL },
{ 0, NULL, NULL }
};
static const char *p11_mechanism_to_name(CK_MECHANISM_TYPE mech)
{
static char temp[64];
@ -5855,6 +6006,30 @@ static CK_MECHANISM_TYPE p11_name_to_mechanism(const char *name)
return 0; /* gcc food */
}
static CK_RSA_PKCS_MGF_TYPE p11_name_to_mgf(const char *name)
{
struct mech_info *mi;
for (mi = p11_mgf; mi->name; mi++) {
if (!strcasecmp(mi->name, name))
return mi->mech;
}
util_fatal("Unknown PKCS11 MGF \"%s\"", name);
}
static const char *p11_mgf_to_name(CK_RSA_PKCS_MGF_TYPE mgf)
{
static char temp[64];
struct mech_info *mi;
for (mi = p11_mgf; mi->name; mi++) {
if (mi->mech == mgf)
return mi->name;
}
snprintf(temp, sizeof(temp), "mgf-0x%lX", (unsigned long) mgf);
return temp;
}
static const char * CKR2Str(CK_ULONG res)
{
switch (res) {

View File

@ -232,7 +232,8 @@ void util_hex_dump_asc(FILE *f, const u8 *in, size_t count, int addr)
}
}
void util_print_usage_and_die(const char *app_name, const struct option options[],
NORETURN void
util_print_usage_and_die(const char *app_name, const struct option options[],
const char *option_help[], const char *args)
{
int i;
@ -343,7 +344,7 @@ const char * util_acl_to_str(const sc_acl_entry_t *e)
return line;
}
void
NORETURN void
util_fatal(const char *fmt, ...)
{
va_list ap;

View File

@ -23,15 +23,28 @@
extern "C" {
#endif
#if _MSC_VER >= 1310
/* MS Visual Studio 2003/.NET Framework 1.1 or newer */
# define NORETURN _declspec( noreturn)
#elif __GNUC__ > 2 || (__GNUC__ == 2 && (__GNUC_MINOR__ >= 5)) || (defined __clang__)
# define NORETURN __attribute__ ((noreturn))
#elif __cplusplus >= 201103L
# define NORETURN [[noreturn]]
#elif __STDC_VERSION__ >= 201112L
# define NORETURN _Noreturn
#else
# define NORETURN
#endif
void util_print_binary(FILE *f, const u8 *buf, int count);
void util_hex_dump(FILE *f, const u8 *in, int len, const char *sep);
void util_hex_dump_asc(FILE *f, const u8 *in, size_t count, int addr);
void util_print_usage_and_die(const char *app_name, const struct option options[],
NORETURN void util_print_usage_and_die(const char *app_name, const struct option options[],
const char *option_help[], const char *args);
const char * util_acl_to_str(const struct sc_acl_entry *e);
void util_warn(const char *fmt, ...);
void util_error(const char *fmt, ...);
void util_fatal(const char *fmt, ...);
NORETURN void util_fatal(const char *fmt, ...);
/* All singing all dancing card connect routine */
int util_connect_card_ex(struct sc_context *, struct sc_card **, const char *reader_id, int do_wait, int do_lock, int verbose);
int util_connect_card(struct sc_context *, struct sc_card **, const char *reader_id, int do_wait, int verbose);