#ifdef HAVE_XKEY_PROVIDER
static XKEY_EXTERNAL_SIGN_fn xkey_pkcs11h_sign;
+#if PKCS11H_VERSION > ((1<<16) | (27<<8)) /* version > 1.27 */
+
+/* Table linking OpenSSL digest NID with CKM and CKG constants in PKCS#11 */
+#define MD_TYPE(n) {NID_sha##n, CKM_SHA##n, CKG_MGF1_SHA##n}
+static const struct
+{
+ int nid;
+ unsigned long ckm_id;
+ unsigned long mgf_id;
+} mdtypes[] = {MD_TYPE(224), MD_TYPE(256), MD_TYPE(384), MD_TYPE(512),
+ {NID_sha1, CKM_SHA_1, CKG_MGF1_SHA1}, /* SHA_1 naming is an oddity */
+ {NID_undef, 0, 0}};
+
+/* From sigalg, derive parameters for pss signature and fill in pss_params.
+ * Its of type CK_RSA_PKCS_PSS_PARAMS struct with three fields to be filled in:
+ * {enum hashAlg, enum mgf, ulong sLen}
+ * where hashAlg is CKM_SHA256 etc., mgf is CKG_MGF1_SHA256 etc.
+ */
+static int
+set_pss_params(CK_RSA_PKCS_PSS_PARAMS *pss_params, XKEY_SIGALG sigalg,
+ pkcs11h_certificate_t cert)
+{
+ int ret = 0;
+ X509 *x509 = NULL;
+ EVP_PKEY *pubkey = NULL;
+
+ if ((x509 = pkcs11h_openssl_getX509(cert)) == NULL
+ || (pubkey = X509_get0_pubkey(x509)) == NULL)
+ {
+ msg(M_WARN, "PKCS#11: Unable get public key");
+ goto cleanup;
+ }
+
+ /* map mdname to CKM and CKG constants for hash and mgf algorithms */
+ int i = 0;
+ int nid = OBJ_sn2nid(sigalg.mdname);
+ while (mdtypes[i].nid != NID_undef && mdtypes[i].nid != nid)
+ {
+ i++;
+ }
+ pss_params->hashAlg = mdtypes[i].ckm_id;
+ pss_params->mgf = mdtypes[i].mgf_id;
+
+ /* determine salt length */
+ int mdsize = EVP_MD_size(EVP_get_digestbyname(sigalg.mdname));
+
+ int saltlen = -1;
+ if (!strcmp(sigalg.saltlen, "digest")) /* same as digest size */
+ {
+ saltlen = mdsize;
+ }
+ else if (!strcmp(sigalg.saltlen, "max")) /* maximum possible value */
+ {
+ saltlen = xkey_max_saltlen(EVP_PKEY_get_bits(pubkey), mdsize);
+ }
+
+ if (saltlen < 0 || pss_params->hashAlg == 0)
+ {
+ msg(M_WARN, "WARN: invalid RSA_PKCS1_PSS parameters: saltlen = <%s> "
+ "mdname = <%s>.", sigalg.saltlen, sigalg.mdname);
+ goto cleanup;
+ }
+ pss_params->sLen = (unsigned long) saltlen; /* saltlen >= 0 at this point */
+
+ msg(D_XKEY, "set_pss_params: sLen = %lu, hashAlg = %lu, mgf = %lu",
+ pss_params->sLen, pss_params->hashAlg, pss_params->mgf);
+
+ ret = 1;
+
+cleanup:
+ if (x509)
+ {
+ X509_free(x509);
+ }
+ return ret;
+}
+
+#else
+
+/* Make set_pss_params a no-op that always succeeds */
+#define set_pss_params(...) (1)
+
+/* Use a wrapper for pkcs11h_certificate_signAny_ex() for versions < 1.28
+ * where its not available.
+ * We just call pkcs11h_certificate_signAny() unless the padding
+ * is PSS in which case we return an error.
+ */
+static CK_RV
+pkcs11h_certificate_signAny_ex(const pkcs11h_certificate_t cert,
+ const CK_MECHANISM *mech, const unsigned char *tbs,
+ size_t tbslen, unsigned char *sig, size_t *siglen)
+{
+ if (mech->mechanism == CKM_RSA_PKCS_PSS)
+ {
+ msg(M_NONFATAL, "PKCS#11: Error: PSS padding is not supported by "
+ "this version of pkcs11-helper library.");
+ return CKR_MECHANISM_INVALID;
+ }
+ return pkcs11h_certificate_signAny(cert, mech->mechanism, tbs, tbslen, sig, siglen);
+}
+#endif /* PKCS11H_VERSION > 1.27 */
+
/**
* Sign op called from xkey provider
*
- * We support ECDSA, RSA_NO_PADDING, RSA_PKCS1_PADDING
+ * We support ECDSA, RSA_NO_PADDING, RSA_PKCS1_PADDING, RSA_PKCS_PSS_PADDING
*/
static int
xkey_pkcs11h_sign(void *handle, unsigned char *sig,
if (!strcmp(sigalg.op, "DigestSign"))
{
- dmsg(D_LOW, "xkey_pkcs11h_sign: computing digest");
+ msg(D_XKEY, "xkey_pkcs11h_sign: computing digest");
if (xkey_digest(tbs, tbslen, buf, &buflen, sigalg.mdname))
{
tbs = buf;
if (!strcmp(sigalg.keytype, "EC"))
{
+ msg(D_XKEY, "xkey_pkcs11h_sign: signing with EC key");
mech.mechanism = CKM_ECDSA;
}
else if (!strcmp(sigalg.keytype, "RSA"))
{
+ msg(D_XKEY, "xkey_pkcs11h_sign: signing with RSA key: padmode = %s",
+ sigalg.padmode);
if (!strcmp(sigalg.padmode,"none"))
{
mech.mechanism = CKM_RSA_X_509;
}
else if (!strcmp(sigalg.padmode, "pss"))
{
- msg(M_NONFATAL, "PKCS#11: Error: PSS padding is not yet supported.");
- return 0;
+ CK_RSA_PKCS_PSS_PARAMS pss_params = {0};
+ mech.mechanism = CKM_RSA_PKCS_PSS;
+
+ if (!set_pss_params(&pss_params, sigalg, cert))
+ {
+ return 0;
+ }
+
+ mech.pParameter = &pss_params;
+ mech.ulParameterLen = sizeof(pss_params);
}
else if (!strcmp(sigalg.padmode, "pkcs1"))
{
ASSERT(0); /* coding error -- we couldnt have created any such key */
}
- return CKR_OK == pkcs11h_certificate_signAny(cert, mech.mechanism,
+ return CKR_OK == pkcs11h_certificate_signAny_ex(cert, &mech,
tbs, tbslen, sig, siglen);
}