Skip to content

Commit

Permalink
Fix EC signature handling for OpenSSL (Issue #50)
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelrsweet committed Apr 10, 2023
1 parent 900db19 commit c331184
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 6 deletions.
44 changes: 38 additions & 6 deletions cups/jwt.c
Original file line number Diff line number Diff line change
Expand Up @@ -316,8 +316,23 @@ cupsJWTHasValidSignature(

if ((ec = make_ec_key(jwk, true)) != NULL)
{
ret = ECDSA_verify(0, hash, hash_len, jwt->signature, jwt->sigsize, ec) == 1;

// Convert binary signature into ECDSA signature for OpenSSL
ECDSA_SIG *ec_sig; // EC signature
BIGNUM *r, *s; // Signature coordinates
int sig_len; // Size of coordinates

ec_sig = ECDSA_SIG_new();
sig_len = (int)jwt->sigsize / 2;
r = BN_new();
s = BN_new();
BN_bin2bn(jwt->signature, sig_len, r);
BN_bin2bn(jwt->signature + sig_len, sig_len, s);
ECDSA_SIG_set0(ec_sig, r, s);

// Verify signature and clean up...
ret = ECDSA_do_verify(hash, hash_len, ec_sig, ec) == 1;

ECDSA_SIG_free(ec_sig);
EC_KEY_free(ec);
}

Expand Down Expand Up @@ -1325,17 +1340,34 @@ make_signature(cups_jwt_t *jwt, // I - JWT
#ifdef HAVE_OPENSSL
unsigned char hash[128]; // SHA-256/384/512 hash
ssize_t hash_len; // Length of hash
unsigned siglen = (unsigned)*sigsize;
// Length of signature
unsigned sig_len; // Length of signature coordinate
EC_KEY *ec; // EC private key
ECDSA_SIG *ec_sig; // EC signature
const BIGNUM *r, *s; // Signature coordinates
unsigned r_len, s_len; // Length of coordinates
static unsigned sig_sizes[3] = // Sizes of signatures
{ 64, 96, 132 };

if ((ec = make_ec_key(jwk, false)) != NULL)
{
hash_len = cupsHashData(cups_jwa_algorithms[alg], text, text_len, hash, sizeof(hash));
if (ECDSA_sign(0, hash, hash_len, signature, &siglen, ec) == 1)
if ((ec_sig = ECDSA_do_sign(hash, hash_len, ec)) != NULL)
{
*sigsize = siglen;
// Get the raw coordinates...
ECDSA_SIG_get0(ec_sig, &r, &s);
r_len = (unsigned)BN_num_bytes(r);
s_len = (unsigned)BN_num_bytes(s);
*sigsize = sig_sizes[alg - CUPS_JWA_ES256];
sig_len = *sigsize / 2;
ret = true;

// 0-pad raw coordinates
memset(signature, 0, *sigsize);
BN_bn2bin(r, signature + sig_len - r_len);
BN_bn2bin(s, signature + *sigsize - s_len);

// Free the signature
ECDSA_SIG_free(ec_sig);
}

EC_KEY_free(ec);
Expand Down
51 changes: 51 additions & 0 deletions cups/testjwt.c
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,57 @@ main(int argc, // I - Number of command-line arguments
cupsJSONDelete(jwk);
cupsJSONDelete(pubjwk);

testBegin("cupsJWTMakePrivateKey(ES256)");
jwk = cupsJWTMakePrivateKey(CUPS_JWA_ES256);
testEnd(jwk != NULL);

testBegin("cupsJWTMakePublicKey(ES256)");
pubjwk = cupsJWTMakePublicKey(jwk);
testEnd(pubjwk != NULL);

testBegin("cupsJWTSign(ES256)");
testEnd(cupsJWTSign(jwt, CUPS_JWA_ES256, jwk));

testBegin("cupsJWTHasValidSignature(ES256)");
testEnd(cupsJWTHasValidSignature(jwt, pubjwk));

cupsJSONDelete(jwk);
cupsJSONDelete(pubjwk);

testBegin("cupsJWTMakePrivateKey(ES384)");
jwk = cupsJWTMakePrivateKey(CUPS_JWA_ES384);
testEnd(jwk != NULL);

testBegin("cupsJWTMakePublicKey(ES384)");
pubjwk = cupsJWTMakePublicKey(jwk);
testEnd(pubjwk != NULL);

testBegin("cupsJWTSign(ES384)");
testEnd(cupsJWTSign(jwt, CUPS_JWA_ES384, jwk));

testBegin("cupsJWTHasValidSignature(ES384)");
testEnd(cupsJWTHasValidSignature(jwt, pubjwk));

cupsJSONDelete(jwk);
cupsJSONDelete(pubjwk);

testBegin("cupsJWTMakePrivateKey(ES512)");
jwk = cupsJWTMakePrivateKey(CUPS_JWA_ES512);
testEnd(jwk != NULL);

testBegin("cupsJWTMakePublicKey(ES512)");
pubjwk = cupsJWTMakePublicKey(jwk);
testEnd(pubjwk != NULL);

testBegin("cupsJWTSign(ES512)");
testEnd(cupsJWTSign(jwt, CUPS_JWA_ES512, jwk));

testBegin("cupsJWTHasValidSignature(ES512)");
testEnd(cupsJWTHasValidSignature(jwt, pubjwk));

cupsJSONDelete(jwk);
cupsJSONDelete(pubjwk);

testBegin("cupsJWTDelete()");
cupsJWTDelete(jwt);
testEnd(true);
Expand Down

0 comments on commit c331184

Please sign in to comment.