Implement functionality for direct use of composite signature algorithms#23416
Implement functionality for direct use of composite signature algorithms#23416levitte wants to merge 5 commits intoopenssl:masterfrom
Conversation
|
This is based on the design in #22672. |
|
Pending: modifications of our providers to support known composite algorithms, along with tests |
28c2b94 to
23e5d2a
Compare
|
The algorithm lifecycle documentation will also need adjusting in |
|
For proof of concept, RSA+hash support for Other algorithms will get the same kind of additions, but in a subsequent PR, so as not to make this one larger. There is example code in the I will try to extend |
7f6be34 to
95531a0
Compare
|
Haha! I've got a simple test working. #include <unistd.h>
#include <string.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/rsa.h>
int main()
{
EVP_PKEY *pk;
size_t keysize_bits = 4096;
size_t keysize_bytes = keysize_bits / 8;
pk = EVP_PKEY_Q_keygen(NULL, NULL, "rsa", keysize_bits);
if (pk == NULL) {
fprintf(stderr, "No key created\n");
ERR_print_errors_fp(stderr);
exit(1);
}
const unsigned char message[] = "\
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod \
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, \
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo \
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse \
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non \
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\
";
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pk, NULL);
/* ---------------------------------------------------------------------- */
/* Signature, attempt 1, with RSA-SHA256 */
EVP_SIGNATURE *sig1alg = EVP_SIGNATURE_fetch(NULL, "RSA-SHA256", NULL);
if (!ctx) {
fprintf(stderr, "No EVP_PKEY context created\n");
ERR_print_errors_fp(stderr);
exit(1);
}
if (!sig1alg) {
fprintf(stderr, "No EVP_SIGNATURE fetched\n");
ERR_print_errors_fp(stderr);
exit(1);
}
if (EVP_PKEY_sign_init_for_message(ctx, sig1alg, NULL) <= 0) {
fprintf(stderr, "Error trying to initialize sign with RSA-SHA256\n");
ERR_print_errors_fp(stderr);
exit(1);
}
unsigned char sig1[keysize_bytes];
size_t sig1len = sizeof(sig1);
if (EVP_PKEY_sign(ctx, sig1, &sig1len, message, sizeof(message) - 1) <= 0) {
fprintf(stderr, "Error trying to sign with RSA-SHA256 oneshot\n");
ERR_print_errors_fp(stderr);
exit(1);
}
/* ---------------------------------------------------------------------- */
/* Signature, attempt 2, with implicit RSA (through pk) + explicit SHA256 */
char *md2name = "sha256";
unsigned char md2[256 / 8]; /* SHA256 => 256 bits of output */
size_t md2len = sizeof(md2);
if (EVP_Q_digest(NULL, md2name, NULL, message, sizeof(message) - 1,
md2, &md2len) <= 0) {
fprintf(stderr, "Error trying hash the message with SHA256\n");
ERR_print_errors_fp(stderr);
exit(1);
}
if (EVP_PKEY_sign_init(ctx) <= 0) {
fprintf(stderr, "Error trying to initialize sign with pk\n");
ERR_print_errors_fp(stderr);
exit(1);
}
if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0) {
fprintf(stderr, "Error trying to set RSA_PKCS1_PADDING\n");
ERR_print_errors_fp(stderr);
exit(1);
}
if (EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha256()) <= 0) {
fprintf(stderr, "Error trying to set signature MD\n");
ERR_print_errors_fp(stderr);
exit(1);
}
unsigned char sig2[keysize_bytes];
size_t sig2len = sizeof(sig2);
if (EVP_PKEY_sign(ctx, sig2, &sig2len, md2, md2len) <= 0) {
fprintf(stderr, "Error trying to sign with oneshot\n");
ERR_print_errors_fp(stderr);
exit(1);
}
printf("SIG1[%zu]: ", sig1len);
for (size_t i = 0; i < sig1len; i++) printf("%02x", sig1[i]);
printf("\n");
printf("SIG2[%zu]: ", sig2len);
for (size_t i = 0; i < sig2len; i++) printf("%02x", sig2[i]);
printf("\n");
if (sig1len != sig2len)
printf("Different lengths!\n");
else if (memcmp(sig1, sig2, sig1len) != 0)
printf("Different signatures!\n");
exit(0);
} |
95531a0 to
94868c4
Compare
dd039db to
67663f1
Compare
|
The latest changes are a direct result of API discussions in My li'le test program got updated accordingly: #include <unistd.h>
#include <string.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/rsa.h>
int main()
{
const unsigned char message[] = "\
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod \
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, \
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo \
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse \
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non \
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\
";
size_t messagelen = sizeof(message) - 1;
char *hashname = "sha256";
unsigned char digest[256 / 8]; /* SHA256 => 256 bits of output */
size_t digestlen = sizeof(digest);
if (EVP_Q_digest(NULL, hashname, NULL, message, messagelen,
digest, &digestlen) <= 0) {
fprintf(stderr, "Error trying hash the message with SHA256\n");
ERR_print_errors_fp(stderr);
exit(1);
}
EVP_PKEY *pk;
size_t keysize_bits = 4096;
size_t keysize_bytes = keysize_bits / 8;
pk = EVP_PKEY_Q_keygen(NULL, NULL, "rsa", keysize_bits);
if (pk == NULL) {
fprintf(stderr, "No key created\n");
ERR_print_errors_fp(stderr);
exit(1);
}
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pk, NULL);
EVP_SIGNATURE *sigalg = EVP_SIGNATURE_fetch(NULL, "RSA-SHA256", NULL);
if (!ctx) {
fprintf(stderr, "No EVP_PKEY context created\n");
ERR_print_errors_fp(stderr);
exit(1);
}
if (!sigalg) {
fprintf(stderr, "No EVP_SIGNATURE fetched\n");
ERR_print_errors_fp(stderr);
exit(1);
}
/* ---------------------------------------------------------------------- */
/* Signature, attempt 1, of the message directly with RSA-SHA256 */
if (EVP_PKEY_sign_message_init(ctx, sigalg, NULL) <= 0) {
fprintf(stderr, "Error trying to initialize sign of message with RSA-SHA256\n");
ERR_print_errors_fp(stderr);
exit(1);
}
unsigned char sig1[keysize_bytes];
size_t sig1len = sizeof(sig1);
if (EVP_PKEY_sign(ctx, sig1, &sig1len, message, messagelen) <= 0) {
fprintf(stderr, "Error trying to sign message with RSA-SHA256 oneshot\n");
ERR_print_errors_fp(stderr);
exit(1);
}
/* ---------------------------------------------------------------------- */
/* Signature, attempt 2, of the pre-hashed message digest with RSA-SHA256 */
if (EVP_PKEY_sign_init_ex2(ctx, sigalg, NULL) <= 0) {
fprintf(stderr, "Error trying to initialize sign of message digest with RSA-SHA256\n");
ERR_print_errors_fp(stderr);
exit(1);
}
unsigned char sig2[keysize_bytes];
size_t sig2len = sizeof(sig2);
if (EVP_PKEY_sign(ctx, sig2, &sig2len, digest, digestlen) <= 0) {
fprintf(stderr, "Error trying to sign message digest with RSA-SHA256 oneshot\n");
ERR_print_errors_fp(stderr);
exit(1);
}
/* ---------------------------------------------------------------------- */
/* Signature, attempt 3, with implicit RSA (through pk) + explicit SHA256 */
if (EVP_PKEY_sign_init(ctx) <= 0) {
fprintf(stderr, "Error trying to initialize sign with pk\n");
ERR_print_errors_fp(stderr);
exit(1);
}
if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0) {
fprintf(stderr, "Error trying to set RSA_PKCS1_PADDING\n");
ERR_print_errors_fp(stderr);
exit(1);
}
if (EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha256()) <= 0) {
fprintf(stderr, "Error trying to set signature hash\n");
ERR_print_errors_fp(stderr);
exit(1);
}
unsigned char sig3[keysize_bytes];
size_t sig3len = sizeof(sig3);
if (EVP_PKEY_sign(ctx, sig3, &sig3len, digest, digestlen) <= 0) {
fprintf(stderr, "Error trying to sign message digest with pk\n");
ERR_print_errors_fp(stderr);
exit(1);
}
printf("SIG1[%zu]: ", sig1len);
for (size_t i = 0; i < sig1len; i++) printf("%02x", sig1[i]);
printf("\n");
printf("SIG2[%zu]: ", sig2len);
for (size_t i = 0; i < sig2len; i++) printf("%02x", sig2[i]);
printf("\n");
printf("SIG3[%zu]: ", sig3len);
for (size_t i = 0; i < sig3len; i++) printf("%02x", sig3[i]);
printf("\n");
if (sig1len != sig2len || sig2len != sig3len)
printf("Different lengths!\n");
else if (memcmp(sig1, sig2, sig1len) != 0
|| memcmp(sig2, sig3, sig2len) != 0)
printf("Different signatures!\n");
exit(0);
}Still doesn't complain (I've built OpenSSL in the subdirectory $ cc -o evp-sign -g -O0 -I _build/include/ -I include/ -L _build/ evp-sign.c -l:libcrypto.a
$ ./evp-sign
SIG1[512]: 17e2deedb4573185fac84753e4fbcf218c0823504939209336ead865b75a175536f344932d87cfd5705e2235d7216384de105bbb512721b9a5bc63ae82e2fdf001a1b8faaa05786829ec39cfc60a4f60d1fe831852b649d1a68ad222b4576f55657081effc927234dfbe639e06fa8c8e4961b2bca3fc9a95db44961fef58158d553c191851d534d5beca77dd76f9b9b5380af96be19060299bb8ee46277c32431219c33073aefa7cc9ab2d67a08c11ae4de9ee6ef271f4d33e4c497b9cf4cca5f2e251ae813dd83430e2f5fd37acf4fa050c30a7524cb32e169301780855a71f63b37fe5dbe2800ad41e8a0c816a358a7a249ef97a5caac51e6558ab23861176d2d08900e51d55fd7808948f53f465cf54956bd54e58b5b9f3e27bd2d3eec6b9d98cccfcdf101e4843e252199b50d20f87e14355243670b2fbc47306c39fb6615ca752c7f6a2b96478922f8e235cba99c31eda10bba36da1ed668e87e234a08ef881f8e98deda52b019e88d66ed91327790d12877c6e2cce922ea12ba3c67a0a0943cd7c5b751d1e2effce6a9689b0ba476c9d90eac1e4b6a6481a6a379c2698084f48bdc52ea4ee4f9e60902376f7f2bb6caad7152d3d7a70d9f3fe5ec6f1eacc4e31c5f530b69667d8892bbfb8c42d928ce645684c4bebd3bae46f8f8505e04582f985df30433eb6932e5f6b477f11c0347b3666f75bd5976d71268f28f1e0
SIG2[512]: 17e2deedb4573185fac84753e4fbcf218c0823504939209336ead865b75a175536f344932d87cfd5705e2235d7216384de105bbb512721b9a5bc63ae82e2fdf001a1b8faaa05786829ec39cfc60a4f60d1fe831852b649d1a68ad222b4576f55657081effc927234dfbe639e06fa8c8e4961b2bca3fc9a95db44961fef58158d553c191851d534d5beca77dd76f9b9b5380af96be19060299bb8ee46277c32431219c33073aefa7cc9ab2d67a08c11ae4de9ee6ef271f4d33e4c497b9cf4cca5f2e251ae813dd83430e2f5fd37acf4fa050c30a7524cb32e169301780855a71f63b37fe5dbe2800ad41e8a0c816a358a7a249ef97a5caac51e6558ab23861176d2d08900e51d55fd7808948f53f465cf54956bd54e58b5b9f3e27bd2d3eec6b9d98cccfcdf101e4843e252199b50d20f87e14355243670b2fbc47306c39fb6615ca752c7f6a2b96478922f8e235cba99c31eda10bba36da1ed668e87e234a08ef881f8e98deda52b019e88d66ed91327790d12877c6e2cce922ea12ba3c67a0a0943cd7c5b751d1e2effce6a9689b0ba476c9d90eac1e4b6a6481a6a379c2698084f48bdc52ea4ee4f9e60902376f7f2bb6caad7152d3d7a70d9f3fe5ec6f1eacc4e31c5f530b69667d8892bbfb8c42d928ce645684c4bebd3bae46f8f8505e04582f985df30433eb6932e5f6b477f11c0347b3666f75bd5976d71268f28f1e0
SIG3[512]: 17e2deedb4573185fac84753e4fbcf218c0823504939209336ead865b75a175536f344932d87cfd5705e2235d7216384de105bbb512721b9a5bc63ae82e2fdf001a1b8faaa05786829ec39cfc60a4f60d1fe831852b649d1a68ad222b4576f55657081effc927234dfbe639e06fa8c8e4961b2bca3fc9a95db44961fef58158d553c191851d534d5beca77dd76f9b9b5380af96be19060299bb8ee46277c32431219c33073aefa7cc9ab2d67a08c11ae4de9ee6ef271f4d33e4c497b9cf4cca5f2e251ae813dd83430e2f5fd37acf4fa050c30a7524cb32e169301780855a71f63b37fe5dbe2800ad41e8a0c816a358a7a249ef97a5caac51e6558ab23861176d2d08900e51d55fd7808948f53f465cf54956bd54e58b5b9f3e27bd2d3eec6b9d98cccfcdf101e4843e252199b50d20f87e14355243670b2fbc47306c39fb6615ca752c7f6a2b96478922f8e235cba99c31eda10bba36da1ed668e87e234a08ef881f8e98deda52b019e88d66ed91327790d12877c6e2cce922ea12ba3c67a0a0943cd7c5b751d1e2effce6a9689b0ba476c9d90eac1e4b6a6481a6a379c2698084f48bdc52ea4ee4f9e60902376f7f2bb6caad7152d3d7a70d9f3fe5ec6f1eacc4e31c5f530b69667d8892bbfb8c42d928ce645684c4bebd3bae46f8f8505e04582f985df30433eb6932e5f6b477f11c0347b3666f75bd5976d71268f28f1e0 |
b9cef54 to
4a0cb39
Compare
005ac0c to
c2447c2
Compare
(in the code, "sigalg" is used to refer to these composite algorithms, which is a nod to libcrypto and libssl, where that term is commonly used for composite algorithms) To make this implementation possible, wrappers were added around the hash function itself, allowing the use of existing hash implementations through their respective OSSL_DISPATCH tables, but also retaining the dynamic fetch of hash implementations when the digest_sign / digest_verify functionality is used. This wrapper allows implementing the RSA+hash composites through simple initializer function and a custom OSSL_DISPATCH table for each.
With these tests, we get to test:
- EVP_PKEY_sign_init_ex()
- EVP_PKEY_verify_init_ex2()
- EVP_PKEY_verify_recover_init_ex2()
- EVP_PKEY_sign_message_init() and friends
- EVP_PKEY_verify_message_init() and friends
A few test cases for RSA-{hash} are added, in
test/recipes/30-test_evp_data/evppkey_rsa_sigalg.txt
It turns out that we didn't allow the combination RSA + SM3 anywhere. This is perfectly reasonable in the FIPS module, but less so in the default provider. This change enables it in the default provider, and adds a simple evp_test stanza for the RSA-SM3 signature scheme.
2231092 to
6509852
Compare
|
@nhorman please reconfirm |
|
Ack, approval holds |
|
This pull request is ready to merge |
| return evp_pkey_signature_init(ctx, algo, EVP_PKEY_OP_VERIFYMSG, params); | ||
| } | ||
|
|
||
| int EVP_PKEY_CTX_set_signature(EVP_PKEY_CTX *ctx, |
There was a problem hiding this comment.
Are the committers that approved this happy with this API that needs to copy the signature? Bear in mind that signatures are getting bigger. Something like LMS can have quite a bit of info in the signature.
There was a problem hiding this comment.
(i.e. A release is being done soon - I dont want new API's going into 3.4 if we cant change them later).
There was a problem hiding this comment.
I did ask questions on this about a month ago, see #22672 (comment)
Those questions are yet unanswered.
At this point, I'd suggest raising an issue on this, or a PR.
There was a problem hiding this comment.
As long as we can pass a param in the future that is a ptr I guess we can deal with it later and then have to handle both cases.
There was a problem hiding this comment.
Sure, leave it 'til later sounds ok to me
|
Merged into master 523187d Enable RSA-SM3 in the default provider |
|
I should probably write a CHANGES entry for this, yeah? |
The following API groups are extended with a new init function, as well as an update and final function, to allow the use of explicitly fetched signature implementations for any composite signature algorithm, like "sha1WithRSAEncryption": - EVP_PKEY_sign - EVP_PKEY_verify - EVP_PKEY_verify_recover To support this, providers are required to add a few new functions, not the least one that declares what key types an signature implementation supports. While at this, the validity check in evp_signature_from_algorithm() is also refactored; the SIGNATURE provider functionality is too complex for counters. It's better, or at least more readable, to check function combinations. Reviewed-by: Tomas Mraz <[email protected]> Reviewed-by: Neil Horman <[email protected]> (Merged from #23416)
(in the code, "sigalg" is used to refer to these composite algorithms, which is a nod to libcrypto and libssl, where that term is commonly used for composite algorithms) To make this implementation possible, wrappers were added around the hash function itself, allowing the use of existing hash implementations through their respective OSSL_DISPATCH tables, but also retaining the dynamic fetch of hash implementations when the digest_sign / digest_verify functionality is used. This wrapper allows implementing the RSA+hash composites through simple initializer function and a custom OSSL_DISPATCH table for each. Reviewed-by: Tomas Mraz <[email protected]> Reviewed-by: Neil Horman <[email protected]> (Merged from #23416)
With these tests, we get to test:
- EVP_PKEY_sign_init_ex()
- EVP_PKEY_verify_init_ex2()
- EVP_PKEY_verify_recover_init_ex2()
- EVP_PKEY_sign_message_init() and friends
- EVP_PKEY_verify_message_init() and friends
A few test cases for RSA-{hash} are added, in
test/recipes/30-test_evp_data/evppkey_rsa_sigalg.txt
Reviewed-by: Tomas Mraz <[email protected]>
Reviewed-by: Neil Horman <[email protected]>
(Merged from #23416)
Reviewed-by: Tomas Mraz <[email protected]> Reviewed-by: Neil Horman <[email protected]> (Merged from #23416)
It turns out that we didn't allow the combination RSA + SM3 anywhere. This is perfectly reasonable in the FIPS module, but less so in the default provider. This change enables it in the default provider, and adds a simple evp_test stanza for the RSA-SM3 signature scheme. Reviewed-by: Tomas Mraz <[email protected]> Reviewed-by: Neil Horman <[email protected]> (Merged from #23416)
The following API groups are extended with a new init function, as well
as an update and final function, to allow the use of explicitly fetched
signature implementations for any composite signature algorithm, like
"sha1WithRSAEncryption":
To support this, providers are required to add a few new functions, not
the least one that declares what key types an signature implementation
supports.