From b110ec2277ba33e0935f3d465a5413f669d8aefc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20P=C3=ADsa=C5=99?= Date: Tue, 11 Oct 2016 16:15:43 +0200 Subject: [PATCH] Port to OpenSSL 1.1.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit OpenSSL 1.1.0 hid ECDSA structure internals and provided methods instead. This patch uses the methods and provides their copies in the case of older OpenSSL. Because the new OpenSSL API, ECDSA_SIG_set0(), cannot set curve parameters individually and ECDSA_SIG_get0() returns yet another reference, it's necessary to duplicate the other unchanged paramater when calling set_r() or set_s(). This patch also stops exporting ECDSA_METHOD functions that were removed from the new OpenSSL. CPAN RT#118330 Signed-off-by: Petr Písař --- ECDSA.xs | 105 ++++++++++++++++++++++++++++++++++++++++-------- t/Crypt-OpenSSL-ECDSA.t | 13 +++++- 2 files changed, 100 insertions(+), 18 deletions(-) diff --git a/ECDSA.xs b/ECDSA.xs index 4016368..3d6e2d1 100644 --- a/ECDSA.xs +++ b/ECDSA.xs @@ -7,9 +7,35 @@ #include #include +#include #include "const-c.inc" + +#if OPENSSL_VERSION_NUMBER >= 0x10100000L +#include +#else +/* ECDSA_SIG_get0() and ECDSA_SIG_set0() copied from OpenSSL 1.1.0b. */ +static void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, + const BIGNUM **ps) { + if (pr != NULL) + *pr = sig->r; + if (ps != NULL) + *ps = sig->s; +} + +static int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s) +{ + if (r == NULL || s == NULL) + return 0; + BN_clear_free(sig->r); + BN_clear_free(sig->s); + sig->r = r; + sig->s = s; + return 1; +} +#endif + MODULE = Crypt::OpenSSL::ECDSA PACKAGE = Crypt::OpenSSL::ECDSA PROTOTYPES: ENABLE @@ -17,7 +43,9 @@ INCLUDE: const-xs.inc BOOT: ERR_load_crypto_strings(); +#if OPENSSL_VERSION_NUMBER >= 0x10002000L && OPENSSL_VERSION_NUMBER < 0x10100000L ERR_load_ECDSA_strings(); +#endif #ECDSA_SIG * #ECDSA_SIG_new() @@ -61,10 +89,16 @@ ECDSA_do_verify(const unsigned char *dgst, const ECDSA_SIG *sig, EC_KEY* eckey); OUTPUT: RETVAL -# These ECDSA_METHOD functions only became available in 1.0.2 +# These ECDSA_METHOD functions only became available in 1.0.2, +# but some of them removed again in 1.1.0. #if OPENSSL_VERSION_NUMBER >= 0x10002000L +int +ECDSA_size(const EC_KEY *eckey) + +#if OPENSSL_VERSION_NUMBER < 0x10100000L + const ECDSA_METHOD * ECDSA_OpenSSL() @@ -77,9 +111,6 @@ ECDSA_get_default_method() int ECDSA_set_method(EC_KEY *eckey, const ECDSA_METHOD *meth) -int -ECDSA_size(const EC_KEY *eckey) - ECDSA_METHOD * ECDSA_METHOD_new(ECDSA_METHOD *ecdsa_method=0) @@ -95,7 +126,7 @@ ECDSA_METHOD_set_name(ECDSA_METHOD *ecdsa_method, char *name) void ERR_load_ECDSA_strings() - +#endif #endif @@ -135,11 +166,13 @@ SV * get_r(ecdsa_sig) ECDSA_SIG *ecdsa_sig PREINIT: + const BIGNUM *r; unsigned char *to; STRLEN len; CODE: to = malloc(sizeof(char) * 128); - len = BN_bn2bin(ecdsa_sig->r, to); + ECDSA_SIG_get0(ecdsa_sig, &r, NULL); + len = BN_bn2bin(r, to); RETVAL = newSVpvn((const char*)to, len); free(to); OUTPUT: @@ -149,11 +182,13 @@ SV * get_s(ecdsa_sig) ECDSA_SIG *ecdsa_sig PREINIT: + const BIGNUM *s; unsigned char *to; STRLEN len; CODE: to = malloc(sizeof(char) * 128); - len = BN_bn2bin(ecdsa_sig->s, to); + ECDSA_SIG_get0(ecdsa_sig, NULL, &s); + len = BN_bn2bin(s, to); RETVAL = newSVpvn((const char*)to, len); free(to); OUTPUT: @@ -164,26 +199,62 @@ set_r(ecdsa_sig, r_SV) ECDSA_SIG *ecdsa_sig SV * r_SV PREINIT: - char *s; + char *string; STRLEN len; + BIGNUM *r; + BIGNUM *s; + const BIGNUM *old_s; CODE: - s = SvPV(r_SV, len); - if (ecdsa_sig->r) - BN_free(ecdsa_sig->r); - ecdsa_sig->r = BN_bin2bn((const unsigned char *)s, len, NULL); + string = SvPV(r_SV, len); + r = BN_bin2bn((const unsigned char *)string, len, NULL); + if (NULL == r) + croak("Could not convert ECDSA parameter string to big number"); + ECDSA_SIG_get0(ecdsa_sig, NULL, &old_s); + if (NULL == old_s) { + s = BN_new(); + } else { + s = BN_dup(old_s); + } + if (NULL == s) { + BN_free(r); + croak("Could not duplicate unchanged ECDSA parameter"); + } + if (!ECDSA_SIG_set0(ecdsa_sig, r, s)) { + BN_free(r); + BN_free(s); + croak("Could not store ECDSA parameters"); + } void set_s(ecdsa_sig, s_SV) ECDSA_SIG *ecdsa_sig SV * s_SV PREINIT: - char *s; + char *string; STRLEN len; + BIGNUM *r; + BIGNUM *s; + const BIGNUM *old_r; CODE: - s = SvPV(s_SV, len); - if (ecdsa_sig->s) - BN_free(ecdsa_sig->s); - ecdsa_sig->s = BN_bin2bn((const unsigned char *)s, len, NULL); + string = SvPV(s_SV, len); + s = BN_bin2bn((const unsigned char *)string, len, NULL); + if (NULL == s) + croak("Could not convert ECDSA parameter string to big number"); + ECDSA_SIG_get0(ecdsa_sig, &old_r, NULL); + if (NULL == old_r) { + r = BN_new(); + } else { + r = BN_dup(old_r); + } + if (NULL == r) { + BN_free(s); + croak("Could not duplicate unchanged ECDSA parameter"); + } + if (!ECDSA_SIG_set0(ecdsa_sig, r, s)) { + BN_free(r); + BN_free(s); + croak("Could not store ECDSA parameters"); + } diff --git a/t/Crypt-OpenSSL-ECDSA.t b/t/Crypt-OpenSSL-ECDSA.t index 7ab584f..3c02025 100644 --- a/t/Crypt-OpenSSL-ECDSA.t +++ b/t/Crypt-OpenSSL-ECDSA.t @@ -6,7 +6,7 @@ use strict; use warnings; -use Test::More tests => 21; +use Test::More tests => 25; BEGIN { use_ok('Crypt::OpenSSL::ECDSA'); use_ok('Crypt::OpenSSL::EC'); }; @@ -77,6 +77,17 @@ $ret = Crypt::OpenSSL::ECDSA::ECDSA_do_verify($digest, $sig, $key); ok($ret); undef $sig; +# Test a signature can be built from scratch +$sig = Crypt::OpenSSL::ECDSA::ECDSA_SIG->new(); +ok($sig, 'Empty Crypt::OpenSSL::ECDSA::ECDSA_SIG object created'); +eval { $sig->set_r($r); }; +ok(!$@, 'R parameter set'); +eval { $sig->set_s($s); }; +ok(!$@, 'S parameter set'); +$ret = Crypt::OpenSSL::ECDSA::ECDSA_do_verify($digest, $sig, $key); +ok($ret, 'built-from-scratch signature matches'); +undef $sig; + # Testing signing and verifying with the _ex version my $dummy = 0; $sig = Crypt::OpenSSL::ECDSA::ECDSA_do_sign_ex($digest, \$dummy, \$dummy, $key); -- 2.7.4