@@ -97,4 +97,24 @@ typedef void (XKEY_PRIVKEY_FREE_fn)(void *handle);
*/
EVP_PKEY *xkey_load_management_key(OSSL_LIB_CTX *libctx, EVP_PKEY *pubkey);
+/**
+ * Add PKCS1 DigestInfo to tbs and return the result in *enc.
+ *
+ * @param enc pointer to output buffer
+ * @param enc_len capacity in bytes of output buffer
+ * @param mdname name of the hash algorithm (SHA256, SHA1 etc.)
+ * @param tbs pointer to digest to be encoded
+ * @param tbslen length of data in bytes
+ *
+ * @return false on error, true on success
+ *
+ * On return enc_len is set to actual size of the result.
+ * enc is NULL or enc_len is not enough to store the result, it is set
+ * to the required size and false is returned.
+ *
+ */
+bool
+encode_pkcs1(unsigned char **enc, size_t *enc_len, const char *mdname,
+ const unsigned char *tbs, size_t tbslen);
+
#endif /* XKEY_PUBLIC_H_ */
@@ -115,6 +115,17 @@ xkey_management_sign(void *unused, unsigned char *sig, size_t *siglen,
/* else assume RSA key */
else if (!strcmp(alg.padmode, "pkcs1"))
{
+ /* management interface expects a pkcs1 encoded digest -- add it */
+ unsigned char enc[EVP_MAX_MD_SIZE + 32]; /* 32 bytes enough for digest inf structure */
+ size_t enc_len = sizeof(enc);
+
+ if (!encode_pkcs1((unsigned char **)&enc, &enc_len, alg.mdname, tbs, tbslen))
+ {
+ return 0;
+ }
+ tbs = enc;
+ tbslen = enc_len;
+
strncpynt(alg_str, "RSA_PKCS1_PADDING", sizeof(alg_str));
}
else if (!strcmp(alg.padmode, "none"))
@@ -155,4 +166,120 @@ xkey_management_sign(void *unused, unsigned char *sig, size_t *siglen,
return (*siglen > 0);
}
+/**
+ * Add PKCS1 DigestInfo to tbs and return the result in *enc.
+ *
+ * @param enc pointer to output buffer
+ * @param enc_len capacity in bytes of output buffer
+ * @param mdname name of the hash algorithm (SHA256, SHA1 etc.)
+ * @param tbs pointer to digest to be encoded
+ * @param tbslen length of data in bytes
+ *
+ * @return false on error, true on success
+ *
+ * On return enc_len is set to actual size of the result.
+ * enc is NULL or enc_len is not enough to store the result, it is set
+ * to the required size and false is returned.
+ *
+ */
+bool
+encode_pkcs1(unsigned char **enc, size_t *enc_len, const char *mdname,
+ const unsigned char *tbs, size_t tbslen)
+{
+ bool ret = false;
+ unsigned char *ptr;
+ int out_len = 0;
+ int tmp_len;
+ X509_ALGOR *algor = NULL;
+ ASN1_STRING *digest = NULL;
+
+ ASSERT(enc_len != NULL);
+ ASSERT(tbs != NULL);
+
+ int nid = OBJ_sn2nid(mdname);
+ if(nid == NID_undef)
+ {
+ msg(M_WARN, "Error: encode_pkcs11: invalid digest name <%s>", mdname);
+ return false;
+ }
+
+ if (nid == NID_md5_sha1) /* no encoding needed -- just copy */
+ {
+ out_len = (int) tbslen;
+ if (enc && (*enc_len >= out_len))
+ {
+ memcpy(*enc, tbs, out_len);
+ }
+ *enc_len = tbslen;
+ ret = 1;
+ goto cleanup;
+ }
+
+ if((algor = X509_ALGOR_new()) == NULL
+ || X509_ALGOR_set0(algor, OBJ_nid2obj(nid), V_ASN1_NULL, NULL) <= 0
+ || (digest = ASN1_STRING_type_new(V_ASN1_OCTET_STRING)) == NULL
+ || ASN1_STRING_set(digest, tbs, tbslen) <= 0)
+ {
+ msg(M_WARN, "Error: encode_pkcs11: failed to create ASN1 strings");
+ goto cleanup;
+ }
+
+ if(algor->algorithm == NULL || OBJ_length(algor->algorithm) == 0)
+ {
+ msg(M_WARN, "Error: encode_pkcs11: invalide digest type(nid = %d)", nid);
+ goto cleanup;
+ }
+
+ /* We want DER encoding of X509_SIG = {algor, digest} which could be
+ * computed as i2d_X509_SIG(), but, unfortunately, the X509_SIG struct
+ * is opaque and has no constructor. Hence we combine the two elements
+ * into a sequence ourselves -- not pretty
+ */
+
+ /* find required size for the buffer */
+ if((tmp_len = i2d_X509_ALGOR(algor, NULL)) < 0)
+ {
+ goto cleanup;
+ }
+ out_len = tmp_len;
+
+ if((tmp_len = i2d_ASN1_OCTET_STRING(digest, NULL)) < 0)
+ {
+ goto cleanup;
+ }
+ out_len += tmp_len + 2 ; /* extra 2 bytes for sequence header added below */
+
+ if ((out_len > (int) *enc_len) || !enc)
+ {
+ *enc_len = out_len;
+ goto cleanup;
+ }
+
+ ptr = *enc;
+ *ptr++ = V_ASN1_SEQUENCE | V_ASN1_CONSTRUCTED;
+ *ptr++ = out_len - 2;
+
+ /* compute and append the DER of algor and digest to ptr */
+ i2d_X509_ALGOR(algor, &ptr); /* this advances ptr */
+ i2d_ASN1_OCTET_STRING(digest, &ptr);
+
+ *enc_len = out_len; /* assignment safe as out_len is > 0 at this point */
+ ret = 1;
+
+ dmsg(D_LOW, "encode_pkcs1: digest length = %d encoded length = %d",
+ (int) tbslen, out_len);
+
+cleanup:
+ if(digest)
+ {
+ ASN1_STRING_free(digest);
+ }
+ if(algor)
+ {
+ X509_ALGOR_free(algor);
+ }
+
+ return ret;
+}
+
#endif /* HAVE_XKEY_PROVIDER */