diff --git a/bin/dnssec/dnssec-keygen.c b/bin/dnssec/dnssec-keygen.c index b0dfaee77a..f0a1217504 100644 --- a/bin/dnssec/dnssec-keygen.c +++ b/bin/dnssec/dnssec-keygen.c @@ -139,7 +139,6 @@ usage(void) { "records with (default: 0)\n"); fprintf(stderr, " -T : DNSKEY | KEY (default: DNSKEY; " "use KEY for SIG(0))\n"); - fprintf(stderr, " ECCGOST:\tignored\n"); fprintf(stderr, " -t : " "AUTHCONF | NOAUTHCONF | NOAUTH | NOCONF " "(default: AUTHCONF)\n"); diff --git a/bin/tests/pkcs11/README b/bin/tests/pkcs11/README new file mode 100644 index 0000000000..4155b117f5 --- /dev/null +++ b/bin/tests/pkcs11/README @@ -0,0 +1,14 @@ +"pkcs11-hmacmd5" is here to check for the presence of a known bug in +the Thales nCipher PKCS#11 provider library. To test for the bug, use +pkcs11-hmacmd5 to hash a test vector from RFC 2104, and determine +whether the resulting digest is is correct. For instance: + + echo -n "Hi There" | \ + ./pkcs11-hmacmd5 -p -k '0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b' + +...must return "9294727a3638bb1c13f48ef8158bfc9d". + +If any other value is returned, then the provider library is buggy, +and the compilation flag PKCS11CRYPTOWITHHMAC must *not* be defined. +However, if the correct value is returned, then it is safe to turn +on PKCS11CRYPTOWITHHMAC. (It is off by default.) diff --git a/bin/tests/system/inline/checkdsa.sh.in b/bin/tests/system/inline/checkdsa.sh.in index f9bdcd4f7c..8c1f312873 100644 --- a/bin/tests/system/inline/checkdsa.sh.in +++ b/bin/tests/system/inline/checkdsa.sh.in @@ -12,9 +12,11 @@ # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. -if test "@CHECK_DSA@" -eq 1 -then - exit 0 -else +if [ "@CHECK_DSA@" -eq 0 ]; then exit 1 fi +if [ ! -r /dev/random -o ! -r /dev/urandom ]; then + exit 1 +fi + +exit 0 diff --git a/bin/tests/system/inline/clean.sh b/bin/tests/system/inline/clean.sh index fa96b55242..cbbbbb87fd 100644 --- a/bin/tests/system/inline/clean.sh +++ b/bin/tests/system/inline/clean.sh @@ -87,3 +87,4 @@ rm -f ns3/test-?.bk rm -f ns3/test-?.bk.signed rm -f ns3/test-?.bk.signed.jnl rm -f import.key Kimport* +rm -f checkgost checkdsa checkecdsa diff --git a/bin/tests/system/inline/ns3/sign.sh b/bin/tests/system/inline/ns3/sign.sh index ed85aeacd0..f95ccffe1a 100755 --- a/bin/tests/system/inline/ns3/sign.sh +++ b/bin/tests/system/inline/ns3/sign.sh @@ -104,46 +104,44 @@ zone=externalkey rm -f K${zone}.+*+*.key rm -f K${zone}.+*+*.private -for alg in ECDSAP256SHA256 NSEC3RSASHA1 DSA ECCGOST +for alg in ECCGOST ECDSAP256SHA256 NSEC3RSASHA1 DSA do - - if test $alg = DSA - then - sh ../checkdsa.sh 2> /dev/null || continue - fi - if test $alg = ECCGOST - then - fail=0 - $KEYGEN -q -r ../$RANDFILE -a eccgost test > /dev/null 2>&1 || fail=1 - rm -f Ktest* - [ $fail != 0 ] && continue - fi - if test $alg = ECDSAP256SHA256 - then - fail=0 - $KEYGEN -q -r ../$RANDFILE -a ecdsap256sha256 test > /dev/null 2>&1 || fail=1 - rm -f Ktest* - [ $fail != 0 ] && continue - sh ../checkdsa.sh 2> /dev/null || continue - fi - - test $alg = DSA -a ! -r /dev/random -a ! -r /dev/urandom && continue + case $alg in + DSA) + sh ../checkdsa.sh 2> /dev/null || continue + checkfile=../checkdsa + touch $checkfile ;; + ECCGOST) + fail=0 + $KEYGEN -q -r $RANDFILE -a eccgost test > /dev/null 2>&1 || fail=1 + rm -f Ktest* + [ $fail != 0 ] && continue + checkfile=../checkgost + touch $checkfile ;; + ECDSAP256SHA256) + fail=0 + $KEYGEN -q -r $RANDFILE -a ecdsap256sha256 test > /dev/null 2>&1 || fail=1 + rm -f Ktest* + [ $fail != 0 ] && continue + sh ../checkdsa.sh 2> /dev/null || continue + checkfile=../checkecdsa + touch $checkfile ;; + *) ;; + esac k1=`$KEYGEN -q -r $RANDFILE -a $alg -b 1024 -n zone -f KSK $zone` k2=`$KEYGEN -q -r $RANDFILE -a $alg -b 1024 -n zone $zone` k3=`$KEYGEN -q -r $RANDFILE -a $alg -b 1024 -n zone $zone` - k4=`$KEYGEN -q -r $RANDFILE -a $alg -b 1024 -n zone $zone` - keyname=`$KEYGEN -q -r $RANDFILE -a $alg -b 1024 -n zone $zone` - keyname=`$KEYGEN -q -r $RANDFILE -a $alg -b 1024 -n zone -f KSK $zone` - $DSFROMKEY -T 1200 $keyname >> ../ns1/root.db - rm -f ${k3}.* ${k4}.* + k4=`$KEYGEN -q -r $RANDFILE -a $alg -b 1024 -n zone -f KSK $zone` + $DSFROMKEY -T 1200 $k4 >> ../ns1/root.db - # # Convert k1 and k2 in to External Keys. rm -f $k1.private mv $k1.key a-file - $IMPORTKEY -P now -D now+3600 -f a-file $zone > /dev/null 2>&1 + $IMPORTKEY -P now -D now+3600 -f a-file $zone > /dev/null 2>&1 || + ( echo "importkey failed: $alg"; rm -f $checkfile ) rm -f $k2.private mv $k2.key a-file - $IMPORTKEY -f a-file $zone > /dev/null 2>&1 + $IMPORTKEY -f a-file $zone > /dev/null 2>&1 || + ( echo "importkey failed: $alg"; rm -f $checkfile ) done diff --git a/bin/tests/system/inline/tests.sh b/bin/tests/system/inline/tests.sh index 2c9b5883da..36eb47a04b 100755 --- a/bin/tests/system/inline/tests.sh +++ b/bin/tests/system/inline/tests.sh @@ -847,7 +847,7 @@ $DIG $DIGOPTS @10.53.0.2 -p 5300 test-$zone SOA > dig.out.ns2.$zone.test$n grep "status: NOERROR," dig.out.ns2.$zone.test$n > /dev/null || { ret=1; cat dig.out.ns2.$zone.test$n; } $RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 addzone test-$zone \ '{ type slave; masters { 10.53.0.2; }; file "'test-$zone.bk'"; inline-signing yes; auto-dnssec maintain; allow-transfer { any; }; };' -$RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 delzone test-$zone +$RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 delzone test-$zone > /dev/null 2>&1 done n=`expr $n + 1` @@ -856,28 +856,9 @@ ret=0 $DIG $DIGOPTS @10.53.0.3 -p 5300 dnskey externalkey > dig.out.ns3.test$n for alg in 3 7 12 13 do - if test $alg = 3 - then - sh checkdsa.sh 2>/dev/null || continue; - fi - if test $alg = 12 - then - fail=0 - $KEYGEN -q -r ../$RANDFILE -a eccgost test > /dev/null 2>&1 || fail=1 - rm -f Ktest* - [ $fail != 0 ] && continue - fi - if test $alg = 13 - then - fail=0 - $KEYGEN -q -r ../$RANDFILE -a ecdsap256sha256 test > /dev/null 2>&1 || fail=1 - rm -f Ktest* - [ $fail != 0 ] && continue - # dsa and ecdsa both require a source of randomness when - # generating signatures - sh checkdsa.sh 2>/dev/null || continue; - fi - test $alg = 3 -a ! -r /dev/random -a ! -r /dev/urandom && continue + [ $alg = 3 -a ! -f checkdsa ] && continue; + [ $alg = 12 -a ! -f checkgost ] && continue; + [ $alg = 13 -a ! -f checkecdsa ] && continue; case $alg in 3) echo "I: checking DSA";; diff --git a/config.h.in b/config.h.in index 8d34508d35..adbea81437 100644 --- a/config.h.in +++ b/config.h.in @@ -455,6 +455,9 @@ int sigwait(const unsigned int *set, int *sig); (O_NDELAY/O_NONBLOCK). */ #undef PORT_NONBLOCK +/* Define if GOST private keys are encoded in ASN.1. */ +#undef PREFER_GOSTASN1 + /* The size of `void *', as computed by sizeof. */ #undef SIZEOF_VOID_P diff --git a/config.h.win32 b/config.h.win32 index f3b8fed2c2..db7cd12f2f 100644 --- a/config.h.win32 +++ b/config.h.win32 @@ -340,6 +340,9 @@ typedef __int64 off_t; /* Define if your PKCS11 provider supports GOST. */ @HAVE_PKCS11_GOST@ +/* Define if GOST private keys are encoded in ASN.1. */ +@PREFER_GOSTASN1@ + /* Define to 1 if you have the `readline' function. */ @HAVE_READLINE@ diff --git a/configure b/configure index dfd264cb47..ab116e6ce3 100755 --- a/configure +++ b/configure @@ -2185,7 +2185,7 @@ Optional Packages: --with-pkcs11=PATH Build with PKCS11 support yes|no|path (PATH is for the PKCS11 provider) --with-ecdsa Crypto ECDSA - --with-gost Crypto GOST + --with-gost Crypto GOST yes|no|raw|asn1. --with-libxml2=PATH Build with libxml2 library yes|no|path --with-libjson=PATH Build with libjson0 library yes|no|path --with-purify=PATH use Rational purify @@ -15612,6 +15612,25 @@ else with_gost="auto" fi +gosttype="raw" +case "$with_gost" in + raw) + with_gost="yes" + ;; + asn1) + +$as_echo "#define PREFER_GOSTASN1 1" >>confdefs.h + + gosttype="asn1" + with_gost="yes" + ;; + auto|yes|no) + ;; + *) + as_fn_error $? "unknown GOST private key encoding" "$LINENO" 5 + ;; +esac + case "$use_openssl" in native_pkcs11) { $as_echo "$as_me:${as_lineno-$LINENO}: result: disabled because of native PKCS11" >&5 @@ -15998,7 +16017,7 @@ fi *) case "$have_gost" in yes|no) ;; - *) as_fn_error $? "need --with-gost=[yes or no]" "$LINENO" 5 ;; + *) as_fn_error $? "need --with-gost=[yes, no, raw or asn1]" "$LINENO" 5 ;; esac ;; esac @@ -23679,14 +23698,31 @@ echo "Configuration summary:" echo "------------------------------------------------------------------------" echo "Optional features enabled:" $use_threads && echo " Multiprocessing support (--enable-threads)" - test "$use_geoip" = "no" || echo " GeoIP access control (--with-geoip)" test "$use_gssapi" = "no" || echo " GSS-API (--with-gssapi)" -test "$want_native_pkcs11" = "yes" && \ - echo " Native PKCS#11 support (--enable-native-pkcs11)" -test "$use_pkcs11" = "no" || echo " PKCS#11/Cryptoki support (--with-pkcs11)" -test "$OPENSSL_GOST" = "yes" -o "$PKCS11_GOST" = "yes" && \ - echo " GOST algorithm support (--with-gost)" + +# these lines are only printed if run with --enable-full-report +if test "$enable_full_report" = "yes"; then + test "$enable_ipv6" = "no" -o "$found_ipv6" = "no" || \ + echo " IPv6 support (--enable-ipv6)" + test "X$CRYPTO" = "X" -o "$want_native_pkcs11" = "yes" || \ + echo " OpenSSL cryptography/DNSSEC (--with-openssl)" + test "X$PYTHON" = "X" || echo " Python tools (--with-python)" + test "X$libxml2_libs" = "X" || echo " XML statistics (--with-libxml2)" + test "X$have_libjson" = "X" || echo " JSON statistics (--with-libjson)" +fi + +if test "$use_pkcs11" != "no"; then + if test "$want_native_pkcs11" = "yes"; then + echo " Native PKCS#11/Cryptoki support (--enable-native-pkcs11)" + else + echo " PKCS#11/Cryptoki support using OpenSSL (--with-pkcs11)" + fi + echo " Provider library: $PKCS11_PROVIDER" +fi +if test "$OPENSSL_GOST" = "yes" -o "$PKCS11_GOST" = "yes"; then + echo " GOST algorithm support (encoding: $gosttype) (--with-gost)" +fi test "$OPENSSL_ECDSA" = "yes" -o "$PKCS11_ECDSA" = "yes" && \ echo " ECDSA algorithm support (--with-ecdsa)" test "$enable_fixed" = "yes" && \ @@ -23699,19 +23735,9 @@ test "$want_symtable" = "minimal" && \ echo " Use symbol table for backtrace, named only (--enable-symtable)" test "$want_symtable" = "yes" -o "$want_symtable" = "all" && \ echo " Use symbol table for backtrace, all binaries (--enable-symtable=all)" +test "$use_libtool" = "no" || echo " Use GNU libtool (--with-libtool)" test "$atf" = "no" || echo " Automated Testing Framework (--with-atf)" -# these lines are only printed if run with --enable-full-report -if test "$enable_full_report" = "yes"; then - test "$enable_ipv6" = "no" -o "$found_ipv6" = "no" || \ - echo " IPv6 support (--enable-ipv6)" - test "X$CRYPTO" = "X" -o "$want_native_pkcs11" = "yes" || \ - echo " OpenSSL cryptography/DNSSEC (--with-openssl)" - test "X$PYTHON" = "X" || echo " Python tools (--with-python)" - test "X$libxml2_libs" = "X" || echo " XML statistics (--with-libxml2)" - test "X$have_libjson" = "X" || echo " JSON statistics (--with-libjson)" -fi - echo " Dynamically loadable zone (DLZ) drivers:" test "$use_dlz_bdb" = "no" || \ echo " Berkeley DB (--with-dlz-bdb)" @@ -23737,21 +23763,27 @@ test "$enable_ipv6" = "no" -o "$found_ipv6" = "no" && \ test "$use_geoip" = "no" && echo " GeoIP access control (--with-geoip)" test "$use_gssapi" = "no" && echo " GSS-API (--with-gssapi)" -test "$use_pkcs11" = "no" && echo " PKCS#11/Cryptoki support (--with-pkcs11)" test "$enable_fixed" = "yes" || \ echo " Allow 'fixed' rrset-order (--enable-fixed-rrset)" -test "$want_backtrace" = "yes" || \ - echo " Print backtrace on crash (--enable-backtrace)" -test "$atf" = "no" && echo " Automated Testing Framework (--with-atf)" -test "X$CRYPTO" = "X" -o "$want_native_pkcs11" = "yes" && \ +if test "X$CRYPTO" = "X" -o "$want_native_pkcs11" = "yes" +then echo " OpenSSL cryptography/DNSSEC (--with-openssl)" -test "$want_native_pkcs11" != "yes" && \ - echo " Native PKCS#11 cryptography/DNSSEC (--enable-native-pkcs11)" +elif "$use_pkcs11" = "no"; then + echo " PKCS#11/Cryptoki support (--with-pkcs11)" +fi +test "$want_native_pkcs11" = "yes" || + echo " Native PKCS#11/Cryptoki support (--enable-native-pkcs11)" test "X$CRYPTO" = "X" -o "$OPENSSL_GOST" = "yes" -o "$PKCS11_GOST" = "yes" || \ echo " GOST algorithm support (--with-gost)" test "X$CRYPTO" = "X" -o "$OPENSSL_ECDSA" = "yes" -o "$PKCS11_ECDSA" = "yes" || \ echo " ECDSA algorithm support (--with-ecdsa)" + +test "$want_backtrace" = "yes" || \ + echo " Print backtrace on crash (--enable-backtrace)" +test "$use_libtool" = "yes" || echo " Use GNU libtool (--with-libtool)" +test "$atf" = "no" && echo " Automated Testing Framework (--with-atf)" + test "X$PYTHON" = "X" && echo " Python tools (--with-python)" test "X$libxml2_libs" = "X" && echo " XML statistics (--with-libxml2)" test "X$have_libjson" = "X" && echo " JSON statistics (--with-libjson)" diff --git a/configure.in b/configure.in index 9727af39b6..54c6a4204e 100644 --- a/configure.in +++ b/configure.in @@ -1145,8 +1145,27 @@ OPENSSL_ECDSA="" OPENSSL_GOST="" AC_ARG_WITH(ecdsa, [ --with-ecdsa Crypto ECDSA], with_ecdsa="$withval", with_ecdsa="auto") -AC_ARG_WITH(gost, [ --with-gost Crypto GOST], +AC_ARG_WITH(gost, +[ --with-gost Crypto GOST [yes|no|raw|asn1].], with_gost="$withval", with_gost="auto") +gosttype="raw" +case "$with_gost" in + raw) + with_gost="yes" + ;; + asn1) + AC_DEFINE(PREFER_GOSTASN1, 1, + [Define if GOST private keys are encoded in ASN.1.]) + gosttype="asn1" + with_gost="yes" + ;; + auto|yes|no) + ;; + *) + AC_MSG_ERROR(unknown GOST private key encoding) + ;; +esac + case "$use_openssl" in native_pkcs11) AC_MSG_RESULT(disabled because of native PKCS11) @@ -1418,7 +1437,7 @@ int main() { *) case "$have_gost" in yes|no) ;; - *) AC_MSG_ERROR([need --with-gost=[[yes or no]]]) ;; + *) AC_MSG_ERROR([need --with-gost=[[yes, no, raw or asn1]]]) ;; esac ;; esac @@ -4114,14 +4133,31 @@ echo "Configuration summary:" echo "------------------------------------------------------------------------" echo "Optional features enabled:" $use_threads && echo " Multiprocessing support (--enable-threads)" - test "$use_geoip" = "no" || echo " GeoIP access control (--with-geoip)" test "$use_gssapi" = "no" || echo " GSS-API (--with-gssapi)" -test "$want_native_pkcs11" = "yes" && \ - echo " Native PKCS#11 support (--enable-native-pkcs11)" -test "$use_pkcs11" = "no" || echo " PKCS#11/Cryptoki support (--with-pkcs11)" -test "$OPENSSL_GOST" = "yes" -o "$PKCS11_GOST" = "yes" && \ - echo " GOST algorithm support (--with-gost)" + +# these lines are only printed if run with --enable-full-report +if test "$enable_full_report" = "yes"; then + test "$enable_ipv6" = "no" -o "$found_ipv6" = "no" || \ + echo " IPv6 support (--enable-ipv6)" + test "X$CRYPTO" = "X" -o "$want_native_pkcs11" = "yes" || \ + echo " OpenSSL cryptography/DNSSEC (--with-openssl)" + test "X$PYTHON" = "X" || echo " Python tools (--with-python)" + test "X$libxml2_libs" = "X" || echo " XML statistics (--with-libxml2)" + test "X$have_libjson" = "X" || echo " JSON statistics (--with-libjson)" +fi + +if test "$use_pkcs11" != "no"; then + if test "$want_native_pkcs11" = "yes"; then + echo " Native PKCS#11/Cryptoki support (--enable-native-pkcs11)" + else + echo " PKCS#11/Cryptoki support using OpenSSL (--with-pkcs11)" + fi + echo " Provider library: $PKCS11_PROVIDER" +fi +if test "$OPENSSL_GOST" = "yes" -o "$PKCS11_GOST" = "yes"; then + echo " GOST algorithm support (encoding: $gosttype) (--with-gost)" +fi test "$OPENSSL_ECDSA" = "yes" -o "$PKCS11_ECDSA" = "yes" && \ echo " ECDSA algorithm support (--with-ecdsa)" test "$enable_fixed" = "yes" && \ @@ -4134,19 +4170,9 @@ test "$want_symtable" = "minimal" && \ echo " Use symbol table for backtrace, named only (--enable-symtable)" test "$want_symtable" = "yes" -o "$want_symtable" = "all" && \ echo " Use symbol table for backtrace, all binaries (--enable-symtable=all)" +test "$use_libtool" = "no" || echo " Use GNU libtool (--with-libtool)" test "$atf" = "no" || echo " Automated Testing Framework (--with-atf)" -# these lines are only printed if run with --enable-full-report -if test "$enable_full_report" = "yes"; then - test "$enable_ipv6" = "no" -o "$found_ipv6" = "no" || \ - echo " IPv6 support (--enable-ipv6)" - test "X$CRYPTO" = "X" -o "$want_native_pkcs11" = "yes" || \ - echo " OpenSSL cryptography/DNSSEC (--with-openssl)" - test "X$PYTHON" = "X" || echo " Python tools (--with-python)" - test "X$libxml2_libs" = "X" || echo " XML statistics (--with-libxml2)" - test "X$have_libjson" = "X" || echo " JSON statistics (--with-libjson)" -fi - echo " Dynamically loadable zone (DLZ) drivers:" test "$use_dlz_bdb" = "no" || \ echo " Berkeley DB (--with-dlz-bdb)" @@ -4172,21 +4198,27 @@ test "$enable_ipv6" = "no" -o "$found_ipv6" = "no" && \ test "$use_geoip" = "no" && echo " GeoIP access control (--with-geoip)" test "$use_gssapi" = "no" && echo " GSS-API (--with-gssapi)" -test "$use_pkcs11" = "no" && echo " PKCS#11/Cryptoki support (--with-pkcs11)" test "$enable_fixed" = "yes" || \ echo " Allow 'fixed' rrset-order (--enable-fixed-rrset)" -test "$want_backtrace" = "yes" || \ - echo " Print backtrace on crash (--enable-backtrace)" -test "$atf" = "no" && echo " Automated Testing Framework (--with-atf)" -test "X$CRYPTO" = "X" -o "$want_native_pkcs11" = "yes" && \ +if test "X$CRYPTO" = "X" -o "$want_native_pkcs11" = "yes" +then echo " OpenSSL cryptography/DNSSEC (--with-openssl)" -test "$want_native_pkcs11" != "yes" && \ - echo " Native PKCS#11 cryptography/DNSSEC (--enable-native-pkcs11)" +elif "$use_pkcs11" = "no"; then + echo " PKCS#11/Cryptoki support (--with-pkcs11)" +fi +test "$want_native_pkcs11" = "yes" || + echo " Native PKCS#11/Cryptoki support (--enable-native-pkcs11)" test "X$CRYPTO" = "X" -o "$OPENSSL_GOST" = "yes" -o "$PKCS11_GOST" = "yes" || \ echo " GOST algorithm support (--with-gost)" test "X$CRYPTO" = "X" -o "$OPENSSL_ECDSA" = "yes" -o "$PKCS11_ECDSA" = "yes" || \ echo " ECDSA algorithm support (--with-ecdsa)" + +test "$want_backtrace" = "yes" || \ + echo " Print backtrace on crash (--enable-backtrace)" +test "$use_libtool" = "yes" || echo " Use GNU libtool (--with-libtool)" +test "$atf" = "no" && echo " Automated Testing Framework (--with-atf)" + test "X$PYTHON" = "X" && echo " Python tools (--with-python)" test "X$libxml2_libs" = "X" && echo " XML statistics (--with-libxml2)" test "X$have_libjson" = "X" && echo " JSON statistics (--with-libjson)" diff --git a/lib/dns/openssldsa_link.c b/lib/dns/openssldsa_link.c index 1fae837be3..449c8ac1a7 100644 --- a/lib/dns/openssldsa_link.c +++ b/lib/dns/openssldsa_link.c @@ -573,8 +573,6 @@ openssldsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { isc_mem_t *mctx = key->mctx; #define DST_RET(a) {ret = a; goto err;} - UNUSED(pub); - /* read private key file */ ret = dst__privstruct_parse(key, DST_ALG_DSA, lexer, mctx, &priv); if (ret != ISC_R_SUCCESS) diff --git a/lib/dns/opensslgost_link.c b/lib/dns/opensslgost_link.c index d3cbb4fab8..e896b0abff 100644 --- a/lib/dns/opensslgost_link.c +++ b/lib/dns/opensslgost_link.c @@ -340,7 +340,7 @@ opensslgost_fromdns(dst_key_t *key, isc_buffer_t *data) { return (ISC_R_SUCCESS); } -#ifdef USE_GOSTASN1 +#ifdef PREFER_GOSTASN1 static isc_result_t opensslgost_tofile(const dst_key_t *key, const char *directory) { @@ -429,7 +429,7 @@ opensslgost_tofile(const dst_key_t *key, const char *directory) { } #endif -unsigned char gost_dummy_key[71] = { +static unsigned char gost_dummy_key[71] = { 0x30, 0x45, 0x02, 0x01, 0x00, 0x30, 0x1c, 0x06, 0x06, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x13, 0x30, 0x12, 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, diff --git a/lib/dns/pkcs11dsa_link.c b/lib/dns/pkcs11dsa_link.c index f277a5551d..b4a779791f 100644 --- a/lib/dns/pkcs11dsa_link.c +++ b/lib/dns/pkcs11dsa_link.c @@ -902,6 +902,11 @@ pkcs11dsa_tofile(const dst_key_t *key, const char *directory) { if (key->keydata.pkey == NULL) return (DST_R_NULLKEY); + if (key->external) { + priv.nelements = 0; + return (dst__privstruct_writefile(key, &priv, directory)); + } + dsa = key->keydata.pkey; for (attr = pk11_attribute_first(dsa); @@ -928,12 +933,6 @@ pkcs11dsa_tofile(const dst_key_t *key, const char *directory) { (pub_key == NULL) || (priv_key ==NULL)) return (DST_R_NULLKEY); - if (key->external) { - priv.nelements = 0; - result = dst__privstruct_writefile(key, &priv, directory); - goto fail; - } - priv.elements[cnt].tag = TAG_DSA_PRIME; priv.elements[cnt].length = (unsigned short) prime->ulValueLen; memcpy(bufs[cnt], prime->pValue, prime->ulValueLen); diff --git a/lib/dns/pkcs11ecdsa_link.c b/lib/dns/pkcs11ecdsa_link.c index 572e47e6ec..f45e7337b8 100644 --- a/lib/dns/pkcs11ecdsa_link.c +++ b/lib/dns/pkcs11ecdsa_link.c @@ -757,8 +757,7 @@ pkcs11ecdsa_tofile(const dst_key_t *key, const char *directory) { if (key->external) { priv.nelements = 0; - result = dst__privstruct_writefile(key, &priv, directory); - goto fail; + return (dst__privstruct_writefile(key, &priv, directory)); } ec = key->keydata.pkey; diff --git a/lib/dns/pkcs11gost_link.c b/lib/dns/pkcs11gost_link.c index 81585336ea..7b00805895 100644 --- a/lib/dns/pkcs11gost_link.c +++ b/lib/dns/pkcs11gost_link.c @@ -708,6 +708,68 @@ pkcs11gost_fromdns(dst_key_t *key, isc_buffer_t *data) { return (ISC_R_NOMEMORY); } +static unsigned char gost_private_der[39] = { + 0x30, 0x45, 0x02, 0x01, 0x00, 0x30, 0x1c, 0x06, + 0x06, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x13, 0x30, + 0x12, 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, + 0x23, 0x01, 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, + 0x02, 0x1e, 0x01, 0x04, 0x22, 0x02, 0x20 +}; + +#ifdef PREFER_GOSTASN1 + +static isc_result_t +pkcs11gost_tofile(const dst_key_t *key, const char *directory) { + isc_result_t ret; + iscpk11_object_t *gost; + dst_private_t priv; + unsigned char *buf = NULL; + unsigned int i = 0; + CK_ATTRIBUTE *attr; + int adj; + + if (key->keydata.pkey == NULL) + return (DST_R_NULLKEY); + + if (key->external) { + priv.nelements = 0; + return (dst__privstruct_writefile(key, &priv, directory)); + } + + gost = key->keydata.pkey; + attr = pk11_attribute_bytype(gost, CKA_VALUE2); + if (attr != NULL) { + buf = isc_mem_get(key->mctx, attr->ulValueLen + 39); + if (buf == NULL) + return (ISC_R_NOMEMORY); + priv.elements[i].tag = TAG_GOST_PRIVASN1; + priv.elements[i].length = + (unsigned short) attr->ulValueLen + 39; + memcpy(buf, gost_private_der, 39); + memcpy(buf +39, attr->pValue, attr->ulValueLen); + adj = (int) attr->ulValueLen - 32; + if (adj != 0) { + buf[1] += adj; + buf[36] += adj; + buf[38] += adj; + } + priv.elements[i].data = buf; + i++; + } else + return (DST_R_CRYPTOFAILURE); + + priv.nelements = i; + ret = dst__privstruct_writefile(key, &priv, directory); + + if (buf != NULL) { + memset(buf, 0, attr->ulValueLen); + isc_mem_put(key->mctx, buf, attr->ulValueLen); + } + return (ret); +} + +#else + static isc_result_t pkcs11gost_tofile(const dst_key_t *key, const char *directory) { isc_result_t ret; @@ -722,8 +784,7 @@ pkcs11gost_tofile(const dst_key_t *key, const char *directory) { if (key->external) { priv.nelements = 0; - result = dst__privstruct_writefile(key, &priv, directory); - goto fail; + return (dst__privstruct_writefile(key, &priv, directory)); } gost = key->keydata.pkey; @@ -737,8 +798,8 @@ pkcs11gost_tofile(const dst_key_t *key, const char *directory) { memcpy(buf, attr->pValue, attr->ulValueLen); priv.elements[i].data = buf; i++; - } - /* else return (DST_R_NULLKEY); */ + } else + return (DST_R_CRYPTOFAILURE); priv.nelements = i; ret = dst__privstruct_writefile(key, &priv, directory); @@ -749,6 +810,7 @@ pkcs11gost_tofile(const dst_key_t *key, const char *directory) { } return (ret); } +#endif static isc_result_t pkcs11gost_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { @@ -769,13 +831,24 @@ pkcs11gost_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { DST_RET(DST_R_INVALIDPRIVATEKEY); if (priv.elements[0].tag == TAG_GOST_PRIVASN1) { - dst__privstruct_free(&priv, mctx); - memset(&priv, 0, sizeof(priv)); - isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, - DNS_LOGMODULE_CRYPTO, ISC_LOG_WARNING, - "GostAsn1 private key format is " - "no longer supported\n"); - return (DST_R_INVALIDPRIVATEKEY); + int adj = (int) priv.elements[0].length - (39 + 32); + unsigned char buf[39]; + + if ((adj > 0) || (adj < -31)) + DST_RET(DST_R_INVALIDPRIVATEKEY); + memcpy(buf, gost_private_der, 39); + if (adj != 0) { + buf[1] += adj; + buf[36] += adj; + buf[38] += adj; + } + if (memcmp(priv.elements[0].data, buf, 39) != 0) + DST_RET(DST_R_INVALIDPRIVATEKEY); + priv.elements[0].tag = TAG_GOST_PRIVRAW; + priv.elements[0].length -= 39; + memmove(priv.elements[0].data, + priv.elements[0].data + 39, + 32 + adj); } gost = (iscpk11_object_t *) isc_mem_get(key->mctx, sizeof(*gost)); diff --git a/lib/dns/pkcs11rsa_link.c b/lib/dns/pkcs11rsa_link.c index 66b5ee16da..6e7ad62435 100644 --- a/lib/dns/pkcs11rsa_link.c +++ b/lib/dns/pkcs11rsa_link.c @@ -903,11 +903,17 @@ pkcs11rsa_tofile(const dst_key_t *key, const char *directory) { CK_ATTRIBUTE *d = NULL, *p = NULL, *q = NULL; CK_ATTRIBUTE *dmp1 = NULL, *dmq1 = NULL, *iqmp = NULL; dst_private_t priv; - unsigned char *bufs[8]; + unsigned char *bufs[10]; isc_result_t result; if (key->keydata.pkey == NULL) return (DST_R_NULLKEY); + + if (key->external) { + priv.nelements = 0; + return (dst__privstruct_writefile(key, &priv, directory)); + } + rsa = key->keydata.pkey; for (attr = pk11_attribute_first(rsa); @@ -944,13 +950,7 @@ pkcs11rsa_tofile(const dst_key_t *key, const char *directory) { memset(bufs, 0, sizeof(bufs)); - if (key->external) { - priv.nelements = 0; - result = dst__privstruct_writefile(key, &priv, directory); - goto fail; - } - - for (i = 0; i < 8; i++) { + for (i = 0; i < 10; i++) { bufs[i] = isc_mem_get(key->mctx, modulus->ulValueLen); if (bufs[i] == NULL) { result = ISC_R_NOMEMORY; @@ -1038,7 +1038,7 @@ pkcs11rsa_tofile(const dst_key_t *key, const char *directory) { priv.nelements = i; result = dst__privstruct_writefile(key, &priv, directory); fail: - for (i = 0; i < 8; i++) { + for (i = 0; i < 10; i++) { if (bufs[i] == NULL) break; memset(bufs[i], 0, modulus->ulValueLen); @@ -1374,7 +1374,7 @@ pkcs11rsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { attr = pk11_attribute_bytype(rsa, CKA_PUBLIC_EXPONENT); INSIST(attr != NULL); if (!key->external && - pk11_numbits(attr->pValue, attr->ulValueLen > RSA_MAX_PUBEXP_BITS)) + pk11_numbits(attr->pValue, attr->ulValueLen) > RSA_MAX_PUBEXP_BITS) DST_RET(ISC_R_RANGE); dst__privstruct_free(&priv, mctx); diff --git a/lib/dns/tests/gost_test.c b/lib/dns/tests/gost_test.c index 27edde9c09..68283d0963 100644 --- a/lib/dns/tests/gost_test.c +++ b/lib/dns/tests/gost_test.c @@ -30,10 +30,23 @@ #include "dnstest.h" -#if defined(HAVE_OPENSSL_GOST) || defined(HAVE_PKCS11_GOST) - +#ifdef HAVE_OPENSSL_GOST #include "../dst_gost.h" +#include +#include +#include +#include +#endif +#ifdef HAVE_PKCS11_GOST +#include "../dst_gost.h" +#include +#define WANT_GOST_PARAMS +#include +#include +#endif + +#if defined(HAVE_OPENSSL_GOST) || defined(HAVE_PKCS11_GOST) /* * Test data from Wikipedia GOST (hash function) */ @@ -82,12 +95,12 @@ typedef struct hash_testcase { int repeats; } hash_testcase_t; -ATF_TC(isc_gost); -ATF_TC_HEAD(isc_gost, tc) { +ATF_TC(isc_gost_md); +ATF_TC_HEAD(isc_gost_md, tc) { atf_tc_set_md_var(tc, "descr", "GOST R 34.11-94 examples from Wikipedia"); } -ATF_TC_BODY(isc_gost, tc) { +ATF_TC_BODY(isc_gost_md, tc) { isc_gost_t gost; isc_result_t result; @@ -135,6 +148,7 @@ ATF_TC_BODY(isc_gost, tc) { "46765E71B765472786E4770D565830A76", 1 }, + /* Test 6 */ { TEST_INPUT("ABCDEFGHIJKLMNOPQRSTUVWXYZabcde" @@ -208,6 +222,145 @@ ATF_TC_BODY(isc_gost, tc) { dns_test_end(); } + +ATF_TC(isc_gost_private); +ATF_TC_HEAD(isc_gost_private, tc) { + atf_tc_set_md_var(tc, "descr", "GOST R 34.10-2001 private key"); +} +ATF_TC_BODY(isc_gost_private, tc) { + isc_result_t result; + unsigned char privraw[31] = { + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e + }; +#ifdef HAVE_OPENSSL_GOST + unsigned char rbuf[32]; + unsigned char privasn1[70] = { + 0x30, 0x44, 0x02, 0x01, 0x00, 0x30, 0x1c, 0x06, + 0x06, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x13, 0x30, + 0x12, 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, + 0x23, 0x01, 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, + 0x02, 0x1e, 0x01, 0x04, 0x21, 0x02, 0x1f, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, + 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, + 0x1a, 0x1b, 0x1c, 0x1d, 0x1e + }; + unsigned char abuf[71]; + unsigned char gost_dummy_key[71] = { + 0x30, 0x45, 0x02, 0x01, 0x00, 0x30, 0x1c, 0x06, + 0x06, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x13, 0x30, + 0x12, 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, + 0x23, 0x01, 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, + 0x02, 0x1e, 0x01, 0x04, 0x22, 0x02, 0x20, 0x1b, + 0x3f, 0x94, 0xf7, 0x1a, 0x5f, 0x2f, 0xe7, 0xe5, + 0x74, 0x0b, 0x8c, 0xd4, 0xb7, 0x18, 0xdd, 0x65, + 0x68, 0x26, 0xd1, 0x54, 0xfb, 0x77, 0xba, 0x63, + 0x72, 0xd9, 0xf0, 0x63, 0x87, 0xe0, 0xd6 + }; + EVP_PKEY *pkey; + EC_KEY *eckey; + BIGNUM *privkey; + const BIGNUM *privkey1; + const unsigned char *p; + int len; + unsigned char *q; + + result = dns_test_begin(NULL, ISC_FALSE); + ATF_REQUIRE(result == ISC_R_SUCCESS); + + /* raw parse */ + privkey = BN_bin2bn(privraw, (int) sizeof(privraw), NULL); + ATF_REQUIRE(privkey != NULL); + p = gost_dummy_key; + pkey = NULL; + ATF_REQUIRE(d2i_PrivateKey(NID_id_GostR3410_2001, &pkey, &p, + (long) sizeof(gost_dummy_key)) != NULL); + ATF_REQUIRE(pkey != NULL); + ATF_REQUIRE(EVP_PKEY_bits(pkey) == 256); + eckey = EVP_PKEY_get0(pkey); + ATF_REQUIRE(eckey != NULL); + ATF_REQUIRE(EC_KEY_set_private_key(eckey, privkey) == 1); + BN_clear_free(privkey); + + /* asn1 tofile */ + len = i2d_PrivateKey(pkey, NULL); + ATF_REQUIRE(len == 70); + q = abuf; + ATF_REQUIRE(i2d_PrivateKey(pkey, &q) == len); + ATF_REQUIRE(memcmp(abuf, privasn1, len) == 0); + EVP_PKEY_free(pkey); + + /* asn1 parse */ + p = privasn1; + pkey = NULL; + ATF_REQUIRE(d2i_PrivateKey(NID_id_GostR3410_2001, &pkey, &p, + (long) len) != NULL); + ATF_REQUIRE(pkey != NULL); + eckey = EVP_PKEY_get0(pkey); + ATF_REQUIRE(eckey != NULL); + privkey1 = EC_KEY_get0_private_key(eckey); + len = BN_num_bytes(privkey1); + ATF_REQUIRE(len == 31); + ATF_REQUIRE(BN_bn2bin(privkey1, rbuf) == len); + ATF_REQUIRE(memcmp(rbuf, privraw, len) == 0); + + dns_test_end(); +#else + CK_BBOOL truevalue = TRUE; + CK_BBOOL falsevalue = FALSE; + CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY; + CK_KEY_TYPE keyType = CKK_GOSTR3410; + CK_ATTRIBUTE keyTemplate[] = + { + { CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) }, + { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) }, + { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, + { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, + { CKA_SENSITIVE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, + { CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) }, + { CKA_VALUE, privraw, sizeof(privraw) }, + { CKA_GOSTR3410_PARAMS, pk11_gost_a_paramset, + (CK_ULONG) sizeof(pk11_gost_a_paramset) }, + { CKA_GOSTR3411_PARAMS, pk11_gost_paramset, + (CK_ULONG) sizeof(pk11_gost_paramset) } + }; + CK_MECHANISM mech = { CKM_GOSTR3410_WITH_GOSTR3411, NULL, 0 }; + CK_BYTE sig[64]; + CK_ULONG siglen; + iscpk11_context_t pk11_ctx; + + result = dns_test_begin(NULL, ISC_FALSE); + ATF_REQUIRE(result == ISC_R_SUCCESS); + + /* create the private key */ + memset(&pk11_ctx, 0, sizeof(pk11_ctx)); + ATF_REQUIRE(pk11_get_session(&pk11_ctx, OP_GOST, ISC_FALSE, ISC_FALSE, + NULL, pk11_get_best_token(OP_GOST)) == + ISC_R_SUCCESS); + pk11_ctx.object = CK_INVALID_HANDLE; + pk11_ctx.ontoken = ISC_FALSE; + ATF_REQUIRE(pkcs_C_CreateObject(pk11_ctx.session, keyTemplate, + (CK_ULONG) 9, &pk11_ctx.object) == + CKR_OK); + ATF_REQUIRE(pk11_ctx.object != CK_INVALID_HANDLE); + + /* sign something */ + ATF_REQUIRE(pkcs_C_SignInit(pk11_ctx.session, &mech, + pk11_ctx.object) == CKR_OK); + siglen = 0; + ATF_REQUIRE(pkcs_C_Sign(pk11_ctx.session, sig, 64, + NULL, &siglen) == CKR_OK); + ATF_REQUIRE(siglen == 64); + ATF_REQUIRE(pkcs_C_Sign(pk11_ctx.session, sig, 64, + sig, &siglen) == CKR_OK); + ATF_REQUIRE(siglen == 64); + + dns_test_end(); +#endif +}; #else ATF_TC(untested); ATF_TC_HEAD(untested, tc) { @@ -223,7 +376,8 @@ ATF_TC_BODY(untested, tc) { */ ATF_TP_ADD_TCS(tp) { #if defined(HAVE_OPENSSL_GOST) || defined(HAVE_PKCS11_GOST) - ATF_TP_ADD_TC(tp, isc_gost); + ATF_TP_ADD_TC(tp, isc_gost_md); + ATF_TP_ADD_TC(tp, isc_gost_private); #else ATF_TP_ADD_TC(tp, untested); #endif diff --git a/win32utils/Configure b/win32utils/Configure index 362a86f288..067f15f9a8 100644 --- a/win32utils/Configure +++ b/win32utils/Configure @@ -338,6 +338,7 @@ my @substdefh = ("ALLOW_FILTER_AAAA", "HAVE_PKCS11_GOST", "HAVE_READLINE", "ISC_LIST_CHECKINIT", + "PREFER_GOSTASN1", "WITH_IDN"); # for platform.h @@ -509,7 +510,7 @@ my @help = ( " with-openssl[=PATH] build with OpenSSL yes|no|path\n", " with-pkcs11[=PATH] build with PKCS#11 support yes|no|provider-path\n", " with-ecdsa crypto ECDSA\n", -" with-gost crypto GOST\n", +" with-gost[=ENC] crypto GOST yes|no|raw|ans1\n", " with-gssapi[=PATH] build with MIT KfW GSSAPI yes|no|path\n", " with-libxml2[=PATH] build with libxml2 library yes|no|path\n", " with-geoip[=PATH] build with GeoIP support yes|no|path\n", @@ -547,6 +548,7 @@ my $use_pkcs11 = "no"; my $pkcs11_path = "unknown"; my $use_ecdsa = "auto"; my $use_gost = "auto"; +my $gost_encoding = "raw"; my $use_gssapi = "no"; my $gssapi_path = "C:\\Program\ Files\\MIT\\Kerberos\\"; my $use_geoip = "no"; @@ -757,6 +759,7 @@ sub mywith { $use_gost = "no"; } elsif ($val =~ /^yes$/i) { $use_gost = "yes"; + $gost_encoding = $val; } } elsif ($key =~ /^gssapi$/i) { if ($val !~ /^no$/i) { @@ -943,6 +946,7 @@ if ($verbose) { print "gost: disabled\n"; } else { print "gost: enabled\n"; + print "gost private key encoding: $gost_encoding\n"; } if ($use_gssapi eq "no") { print "gssapi: disabled\n"; @@ -1591,6 +1595,12 @@ if ($use_gost ne "no") { $configdefh{"HAVE_OPENSSL_GOST"} = 1; } +if ($gost_encoding eq "ans1") { + $configdefh{"PREFER_GOSTASN1"} = 1; +} elsif ($gost_encoding ne "raw") { + die "Unrecognized GOST private key encoding: $gost_encoding\n"; +} + # enable-openssl-hash if ($enable_openssl_hash eq "yes") { if ($use_openssl eq "no") {