]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
[master] address several issues with native pkcs11
authorEvan Hunt <each@isc.org>
Sat, 18 Jan 2014 19:51:07 +0000 (11:51 -0800)
committerEvan Hunt <each@isc.org>
Sat, 18 Jan 2014 19:51:07 +0000 (11:51 -0800)
18 files changed:
bin/dnssec/dnssec-keygen.c
bin/tests/pkcs11/README [new file with mode: 0644]
bin/tests/system/inline/checkdsa.sh.in
bin/tests/system/inline/clean.sh
bin/tests/system/inline/ns3/sign.sh
bin/tests/system/inline/tests.sh
config.h.in
config.h.win32
configure
configure.in
lib/dns/openssldsa_link.c
lib/dns/opensslgost_link.c
lib/dns/pkcs11dsa_link.c
lib/dns/pkcs11ecdsa_link.c
lib/dns/pkcs11gost_link.c
lib/dns/pkcs11rsa_link.c
lib/dns/tests/gost_test.c
win32utils/Configure

index b0dfaee77a315a519de1d516100c67d1b577570d..f0a1217504badbe333008b16777439ee80d57ce5 100644 (file)
@@ -139,7 +139,6 @@ usage(void) {
                        "records with (default: 0)\n");
        fprintf(stderr, "    -T <rrtype>: DNSKEY | KEY (default: DNSKEY; "
                        "use KEY for SIG(0))\n");
-       fprintf(stderr, "        ECCGOST:\tignored\n");
        fprintf(stderr, "    -t <type>: "
                        "AUTHCONF | NOAUTHCONF | NOAUTH | NOCONF "
                        "(default: AUTHCONF)\n");
diff --git a/bin/tests/pkcs11/README b/bin/tests/pkcs11/README
new file mode 100644 (file)
index 0000000..4155b11
--- /dev/null
@@ -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 <PIN> -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.)
index f9bdcd4f7ccfda7dc03cdf69d05423d9373648e3..8c1f31287321b128e60b02f9a53c37b7079d5af7 100644 (file)
 # 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
index fa96b55242a2ae024f9f18ff336fb30dfaaa431a..cbbbbb87fd2877866f072d95f373cf52d18d5ada 100644 (file)
@@ -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
index ed85aeacd0b93375fa6286f053876629029a1bac..f95ccffe1a2ca1c11e016e742e6aa46bfeeb2e4a 100755 (executable)
@@ -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
index 2c9b5883da227eb8a0f823e108f8a66f4a3f1c02..36eb47a04bff69f3fb11953ff7c45d34469ad5f8 100755 (executable)
@@ -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";;
index 8d34508d35ba3aa4c6332991c1e844b8a843b94d..adbea81437d79ad44067e3a7cafe081994a31497 100644 (file)
@@ -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
 
index f3b8fed2c2d0a4f9409916099522523a0a0f2ba1..db7cd12f2f6898a790ac4900e23b3c6085dfab37 100644 (file)
@@ -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@
 
index dfd264cb47c6269d20796ac5e897e47824ce6533..ab116e6ce3791fa15926899c034af28ab935fd84 100755 (executable)
--- 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)"
index 9727af39b6657664c827a1498c276f666b8102ea..54c6a4204ef115fec25609364d11998a0d17b937 100644 (file)
@@ -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)"
index 1fae837be3e0bc535f6410509299c2839cf1bb93..449c8ac1a7149959cecb11c832e91179f891f079 100644 (file)
@@ -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)
index d3cbb4fab87f63596facf61d772775be43a4b048..e896b0abff966f30985524438b66997a9b078f73 100644 (file)
@@ -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,
index f277a5551db5019bdc7df041efc70e7cd5e5821f..b4a779791fbf42b781aaf95312473a46afa6e1f3 100644 (file)
@@ -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);
index 572e47e6ec5ad9f43a9d923c0c617184831525f6..f45e7337b85e2c293b69de2084bd3fb8b0b6427d 100644 (file)
@@ -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;
index 81585336eaac8d8e0ae7bae7c0905414c7800220..7b00805895ee6dc6ad5511451053064a8e952f52 100644 (file)
@@ -708,6 +708,16 @@ 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;
@@ -716,14 +726,65 @@ pkcs11gost_tofile(const dst_key_t *key, const char *directory) {
        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;
-               result = dst__privstruct_writefile(key, &priv, directory);
-               goto fail;
+               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;
+       iscpk11_object_t *gost;
+       dst_private_t priv;
+       unsigned char *buf = NULL;
+       unsigned int i = 0;
+       CK_ATTRIBUTE *attr;
+
+       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;
@@ -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));
index 66b5ee16daa4fe3b389c64f8ca840a5416094616..6e7ad624356e971d34b890909d7595052e2894f0 100644 (file)
@@ -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);
index 27edde9c09c314a29344a777ee8d01237b68f87f..68283d0963881fb3e554c0fbc57404b03f8a49f6 100644 (file)
 
 #include "dnstest.h"
 
-#if defined(HAVE_OPENSSL_GOST) || defined(HAVE_PKCS11_GOST)
+#ifdef HAVE_OPENSSL_GOST
+#include "../dst_gost.h"
+#include <openssl/err.h>
+#include <openssl/objects.h>
+#include <openssl/rsa.h>
+#include <openssl/engine.h>
+#endif
 
+#ifdef HAVE_PKCS11_GOST
 #include "../dst_gost.h"
+#include <iscpk11/internal.h>
+#define WANT_GOST_PARAMS
+#include <iscpk11/constants.h>
+#include <pkcs11/pkcs11.h>
+#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
index 362a86f288d8b713ea5a2aa1a17d1e2ce94e5bb1..067f15f9a8d612534fec5a1dea18a778811ba18b 100644 (file)
@@ -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") {