Skip to content

pkey: fix repeated passphrase prompts in OpenSSL::PKey.read #931

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 26 additions & 15 deletions ext/openssl/ossl_pkey.c
Original file line number Diff line number Diff line change
Expand Up @@ -83,41 +83,48 @@ ossl_pkey_wrap(EVP_PKEY *pkey)
# include <openssl/decoder.h>

static EVP_PKEY *
ossl_pkey_read(BIO *bio, const char *input_type, int selection, VALUE pass)
ossl_pkey_read(BIO *bio, const char *input_type, int selection, VALUE pass,
int *retryable)
{
void *ppass = (void *)pass;
OSSL_DECODER_CTX *dctx;
EVP_PKEY *pkey = NULL;
int pos = 0, pos2;

*retryable = 0;
dctx = OSSL_DECODER_CTX_new_for_pkey(&pkey, input_type, NULL, NULL,
selection, NULL, NULL);
if (!dctx)
goto out;
if (OSSL_DECODER_CTX_set_pem_password_cb(dctx, ossl_pem_passwd_cb,
if (selection == EVP_PKEY_KEYPAIR &&
OSSL_DECODER_CTX_set_pem_password_cb(dctx, ossl_pem_passwd_cb,
ppass) != 1)
goto out;
while (1) {
if (OSSL_DECODER_from_bio(dctx, bio) == 1)
goto out;
if (BIO_eof(bio))
break;
if (ERR_GET_REASON(ERR_peek_error()) != ERR_R_UNSUPPORTED)
break;
if (BIO_eof(bio) == 1) {
*retryable = 1;
break;
}
pos2 = BIO_tell(bio);
if (pos2 < 0 || pos2 <= pos)
if (pos2 < 0 || pos2 <= pos) {
*retryable = 1;
break;
}
ossl_clear_error();
pos = pos2;
}
out:
OSSL_BIO_reset(bio);
OSSL_DECODER_CTX_free(dctx);
return pkey;
}

EVP_PKEY *
ossl_pkey_read_generic(BIO *bio, VALUE pass)
{
EVP_PKEY *pkey = NULL;
/* First check DER, then check PEM. */
const char *input_types[] = {"DER", "PEM"};
int input_type_num = (int)(sizeof(input_types) / sizeof(char *));
Expand Down Expand Up @@ -166,18 +173,22 @@ ossl_pkey_read_generic(BIO *bio, VALUE pass)
EVP_PKEY_PUBLIC_KEY
};
int selection_num = (int)(sizeof(selections) / sizeof(int));
int i, j;

for (i = 0; i < input_type_num; i++) {
for (j = 0; j < selection_num; j++) {
pkey = ossl_pkey_read(bio, input_types[i], selections[j], pass);
if (pkey) {
goto out;
for (int i = 0; i < input_type_num; i++) {
for (int j = 0; j < selection_num; j++) {
if (i || j) {
ossl_clear_error();
BIO_reset(bio);
}

int retryable;
EVP_PKEY *pkey = ossl_pkey_read(bio, input_types[i], selections[j],
pass, &retryable);
if (pkey || !retryable)
return pkey;
}
}
out:
return pkey;
return NULL;
}
#else
EVP_PKEY *
Expand Down
127 changes: 127 additions & 0 deletions test/openssl/test_pkey.rb
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,133 @@
assert_not_equal nil, pkey.private_key
end

def test_s_read_pem_unknown_block
# A PEM-encoded certificate and a PEM-encoded private key are combined.
# Check that OSSL_STORE doesn't stop after the first PEM block.
pkey = Fixtures.pkey("rsa-1")
subject = OpenSSL::X509::Name.new([["CN", "test"]])
cert = issue_cert(subject, pkey, 1, [], nil, nil)

input = cert.to_pem + pkey.private_to_pem
decoded = OpenSSL::PKey.read(input)
assert_equal(pkey.private_to_der, decoded.private_to_der)
end

def test_s_read_der_then_pem
# Ensure DER decode -> DER encode round-trip. If the input is valid as both
# DER and PEM (with garbage data before and after the block), DER is
# prioritized.
inner_rsa = Fixtures.pkey("rsa-1")
inner_pem = inner_rsa.private_to_pem

asn1 = OpenSSL::ASN1::Sequence([
OpenSSL::ASN1::Sequence([
OpenSSL::ASN1::ObjectId("rsaEncryption"),
OpenSSL::ASN1::Null(nil)
]),
OpenSSL::ASN1::BitString(
OpenSSL::ASN1::Sequence([
OpenSSL::ASN1::Integer(OpenSSL::BN.new("\n" + inner_pem, 2)),
OpenSSL::ASN1::Integer(65537)
]).to_der
)
])
assert_include(asn1.to_der, inner_pem)

pkey = OpenSSL::PKey.read(asn1.to_der)
assert_equal(asn1.to_der, pkey.to_der)

Check failure on line 97 in test/openssl/test_pkey.rb

View workflow job for this annotation

GitHub Actions / aws-lc-latest

Failure

<"0\x82\f\xE60\r\x06\t*\x86H\x86\xF7\r\x01\x01\x01\x05\x00\x03\x82\f\xD3\x000\x82\f\xCE\x02\x82\f\xC5\n" + "-----BEGIN PRIVATE KEY-----\n" + "MIIJQQIBADANBgkqhkiG9w0BAQEFAASCCSswggknAgEAAoICAQCsgQlRhmteEx9R\n" + "dd2XaAtxetEHhyJY0R5e3lRUsbSc+HKBnAnGKzy06uNc4kSlRdSx+AXfmlCIksPh\n" + "P39WnfMsW0w45CM5HcDGMh6Vsf0o/IYUSv1Nw+2wnbjOFwbtFvA4ZdHiIhwNpPH5\n" + "sItIB3sGMbdcdC3J56kYZFmQbIZS9eM+isdc/51CNCcx3T3C/QYxlKpDTo951RQp\n" + "Dg8lF8wI/6bCMU/6sHc1m5OEXQKw2amiLGAZ2hDn3Vit/mt/YGzzjwmth2omUqUE\n" + "vqtMV/aCUeIL6YTlhGfLtFm2/+oiTJQ2i1Vx7VwTQYWtGYKnD1uq6UMNyAqMWSGK\n" + "FODhWirRRh0noCWDtSvgl6spN/IJpEYXbtV+H+DYDb/pW7zEphjBMDAuf5O+TH05\n" + "NVnW3XnAzsxryEejA2g7SD+VaR6W2AcsyOKuZ64hhDbQFCZ3HZFGBYqXnsPTA783\n" + "QchH4Gbi9wGg0+AyWT2DlYcDqJ0dHxMvE6t0wyZOJZ958HT8XMZcG/sO67Mc3f66\n" + "t0K8bVAgwVDTqQdeGvisLbwptYjGD48kYzygY0Qa0ZYA6+Lg6/4FWwh1sPlJ/Jvi\n" + "djcv2qo+XpPFHExZMqxgJjHXWMLxyK8LM67IvXP7CAggInqIbOt9h/oLYGI1XcEL\n" + "VgK2nZewb4CigjELCMvYI//ngy5GdQIDAQABAoICAA/j7wzQehF3Z3okhl4NGojA\n" + "jILKAvL1iHuqtU/78qxHAp1H12qmzvfHb1w+B57F2Prv4vKfD24VPu//3mYHNMBQ\n" + "RKw0772yLPDU6xZVCAH/iQZThhPkyX9sd/qcCmpKo6Q+VOAkzjq/h/69MYdYERAY\n" + "AlEE7rbbnSr/C3UPWixIND+tnwHFFiJkFXw1ahwNHMXycOC0WukZJLtHbUO4dnYZ\n" + "vq3CxyBLox+QDj2yJ65MzqB+v/eBq+7/58xXVGWuZzrkYTrX74JKOKNAQR1OOQn2\n" + "KwF36GMQGFOecGk4F8RDE6AWo69T8xhe/8ZbRDrJYmNTC3c4hyg4iatjkvePS8RG\n" + "d4DUCXB6qxvCzd9dcyMD6OEvGUmqM+9IApw86LvG7tAImNJIsDMdIM92YaZ/OWtt\n" + "1ZLWHSasLlhlg7JOgtqN+eYCVc02vK2d4+AlX3/XXfpkWsnISLUlU3eTKsL7WJV3\n" + "UT6VYrRTVRDr/bm0m8oVzUj7FOhpRsrXRQ3JxeJvunZmxz/5kyU9GALFaakgeYqG\n" + "fBs7u+1G6eedzrDOG+VBA0daUi+TJC6RXnTqT9vNbDQzoD3wHigIgIhzFylLeeMO\n" + "UfIvs2WQIP7859mnpfdFkX+biCuYDZ2h5vOCWxo0zIYcWukeQerX1jrdjiO0F1b9\n" + "e4G/ToKevivcFd2MTPPBAoIBAQDluPvfs2RksDRSDNVW9jrsxOx6tM4QIi3iLfud\n" + "QuNFDCxIWLPQBYU4HBQIEnk3aoMR6Vt/QVq3hXOumGvISDMvP/3lleL6jHDWWKoI\n" + "eLyId5TbBJyUO3HaMq/artsW8VJofgIoLg3MEk18/3aR1e4CNeRsr+NbCvrh8s2H\n" + "/YoVZQCatia0Z+c6OPIv7JmE/EFq3O0Tnyr9PrWmS8/02It+uvterx+fOvCoYRGF\n" + "cq57KgrqKD1kk9nZVPKQxRS81gkns5hBmu4RgDfOS4RmJ+qaOAXnsGCDt2SQiHbz\n" + "lPMfcI1/cwIxOaOVZXIeOXJ5I9iAhIH0zKxUopC2H5K9hwKFAoIBAQDAPIJyiUDv\n" + "5tAF8QKzoZeLtFjLZhKXHnrZLm+GNKVj0qhaLBUla+IXu5IF1lGcZQqg+/grgtXf\n" + "ijaUmlJJOLleCnsUf3zpV0Z497eniFxdIhk22woiYtUucSOuaRkTF9CXunQyRxT8\n" + "uF4J/94RlWnRnzg7nhYKzoZGb3AdghTKtqD0VESqrFNFU2FBDYQNUarWyVER3AH5\n" + "rKATvprEr+qiyTRFqgvMZmIyfhJvxuknFc6Z575+2rltrJWW19HQOELx4eRw88V5\n" + "AyWXWD4wvsdsg3AdOvTU42bdwVQ7jM4sE47Cz/6+01+K/pL+U7VFBJGiIClsQ0Et\n" + "1JzdXwLLvQ8xAoIBAE5xk3i4/mAvlz4pabRPUqHFQOdJ1E/IDBj/ELuLuqW6WWi+\n" + "+W/gYrRdSi3TeRcGRQmZwQe8Xmjqpi0JmUyD8w6AcIe0XhSmXmWjUzSfXenPw8Hi\n" + "WkF35xHWWxx2txOnhjduR/hGeamk2lcDuQ5lmeehVYYTrbRKFI+RZMO6PSu/GKy7\n" + "5I2YKWpFRdY9mdLCfOgr1rzrjjd58Xd+zd1TEJdO7EVR0Z+C9ejZdK04EwK1wZJh\n" + "+Uzd+/btvgLXeZReFjQ7bJOCfyb0vJmySdzEZqUQ2ltabCquNiXwo4Xb6AVlXrwV\n" + "nrsGbqi2Qni1rzRUnDqOhP394h7ogDfgojAb6S0CggEAVG4/HO8LhlJpqzJfbWXb\n" + "mZBsL2l1YMoSSrEKandU7LLpHjGeWAE6HBJV4BpxXa9DK9F+/h1IshWSQ1JEMcSo\n" + "JZWU2TvlMNcULK0gDITnjEAdsuohWVjvKKaodUHTsX8ULo/F2Q8/OIABTYMDldV5\n" + "1IeJuyWDqNtsPiNTqqInX6E2sBkSz6NAL4KfhGLbTL5BunRRFvb6Jx6acBGXCCv7\n" + "cePNAYveArg1CNg2YMGMRY5eX1pZYH3QU0spqEbB8CHFxVbhbnqikLPBHuey6NXh\n" + "4NcZtrzeK2J1G5B93mnJY7JzUTzpNgbAP9vv06QQSW/oRry5dMNVLTvkaZYBNFql\n" + "AQKCAQB31kBvJP4qi5N+LZ7rIs6izFJl+ex4XTpAAmLmf0Y6118rl+p2YcmokjvB\n" + "u5sKd3SjE94vvWVGOs4Axe59pBF1m19dIycHVOWO142uHV6fnEXjnWsI9H9jq00o\n" + "G8gqeHLXBo7bv+8D6i9eubXuJH2tG4Znb2Ii6uUoDrP/3pR2tJ2mohNMLJONI4Fi\n" + "Dfh/j254aOWkvj7wcmrbCivgJvVJu/wSuoBuxD8nP4ogZSK4UJ81rp3oxw9Fcisa\n" + "DOmmteB+KaRXeePj1DKue4IX89zimwaAho2XcSIZfNG3/nkrsNBVp21tyOj3NERp\n" + "zxCcMPp1L+A58nzYvt+tB8yk1aBA\n" + "-----END PRIVATE KEY-----\n" + "\x02\x03\x01\x00\x01"> expected but was <"0\x82\t'\x02\x01\x00\x02\x82\x02\x01\x00\xAC\x81\tQ\x86k^\x13\x1FQu\xDD\x97h\vqz\xD1\a\x87\"X\xD1\x1E^\xDETT\xB1\xB4\x9C\xF8r\x81\x9C\t\xC6+<\xB4\xEA\xE3\\\xE2D\xA5E\xD4\xB1\xF8\x05\xDF\x9AP\x88\x92\xC3\xE1?\x7FV\x9D\xF3,[L8\xE4#9\x1D\xC0\xC62\x1E\x95\xB1\xFD(\xFC\x86\x14J\xFDM\xC3\xED\xB0\x9D\xB8\xCE\x17\x06\xED\x16\xF08e\xD1\xE2\"\x1C\r\xA4\xF1\xF9\xB0\x8BH\a{\x
assert_not_predicate(pkey, :private?)
end

def test_s_read_passphrase
pkey0 = Fixtures.pkey("rsa-1")
encrypted_pem = pkey0.private_to_pem("AES-256-CBC", "correct_passphrase")
assert_match(/\A-----BEGIN ENCRYPTED PRIVATE KEY-----/, encrypted_pem)

# Correct passphrase passed as the second argument
pkey1 = OpenSSL::PKey.read(encrypted_pem, "correct_passphrase")
assert_equal(pkey0.private_to_der, pkey1.private_to_der)

# Correct passphrase returned by the block. The block gets false
called = 0
flag = nil
pkey2 = OpenSSL::PKey.read(encrypted_pem) { |f|
called += 1
flag = f
"correct_passphrase"
}
assert_equal(pkey0.private_to_der, pkey2.private_to_der)
assert_equal(1, called)
assert_false(flag)

# Incorrect passphrase passed. The block is not called
called = 0
assert_raise(OpenSSL::PKey::PKeyError) {
OpenSSL::PKey.read(encrypted_pem, "incorrect_passphrase") {
called += 1
}
}
assert_equal(0, called)

# Incorrect passphrase returned by the block. The block is called only once
called = 0
assert_raise(OpenSSL::PKey::PKeyError) {
OpenSSL::PKey.read(encrypted_pem) {
called += 1
"incorrect_passphrase"
}
}
assert_equal(1, called)

# Incorrect passphrase returned by the block. The input contains two PEM
# blocks.
called = 0
assert_raise(OpenSSL::PKey::PKeyError) {
OpenSSL::PKey.read(encrypted_pem + encrypted_pem) {
called += 1
"incorrect_passphrase"
}
}
assert_equal(1, called)
end

def test_s_read_passphrase_tty
pkey0 = Fixtures.pkey("rsa-1")
encrypted_pem = pkey0.private_to_pem("AES-256-CBC", "correct_passphrase")

# Correct passphrase passed to OpenSSL's prompt
script = <<~"end;"
require "openssl"
Process.setsid
OpenSSL::PKey.read(#{encrypted_pem.dump})
puts "ok"
end;
assert_in_out_err([*$:.map { |l| "-I#{l}" }, "-e#{script}"],
"correct_passphrase\n") { |stdout, stderr|
assert_equal(["Enter PEM pass phrase:"], stderr)

Check failure on line 166 in test/openssl/test_pkey.rb

View workflow job for this annotation

GitHub Actions / aws-lc-latest

Failure

<["Enter PEM pass phrase:"]> expected but was <["-e:3:in `read': Could not parse PKey: NO_START_LINE (Expecting: PARAMETERS) (OpenSSL::PKey::PKeyError)", "\tfrom -e:3:in `<main>'"]>. diff: - ["Enter PEM pass phrase:"] + ["-e:3:in `read': Could not parse PKey: NO_START_LINE (Expecting: PARAMETERS) (OpenSSL::PKey::PKeyError)", + "\tfrom -e:3:in `<main>'"] folded diff: - ["Enter PEM pass phrase:"] + ["-e:3:in `read': Could not parse PKey: NO_START_LINE (Expecting: PARAMETERS) + (OpenSSL::PKey::PKeyError)", + "\tfrom -e:3:in `<main>'"]

Check failure on line 166 in test/openssl/test_pkey.rb

View workflow job for this annotation

GitHub Actions / windows-latest 3.1

Failure

<["Enter PEM pass phrase:"]> expected but was <["-e:2:in `setsid': setsid() function is unimplemented on this machine (NotImplementedError)", "\tfrom -e:2:in `<main>'"]>. diff: - ["Enter PEM pass phrase:"] + ["-e:2:in `setsid': setsid() function is unimplemented on this machine (NotImplementedError)", + "\tfrom -e:2:in `<main>'"] folded diff: - ["Enter PEM pass phrase:"] + ["-e:2:in `setsid': setsid() function is unimplemented on this machine (NotImp + lementedError)", + "\tfrom -e:2:in `<main>'"]

Check failure on line 166 in test/openssl/test_pkey.rb

View workflow job for this annotation

GitHub Actions / windows-latest 3.0

Failure

<["Enter PEM pass phrase:"]> expected but was <["-e:2:in `setsid': setsid() function is unimplemented on this machine (NotImplementedError)", "\tfrom -e:2:in `<main>'"]>. diff: - ["Enter PEM pass phrase:"] + ["-e:2:in `setsid': setsid() function is unimplemented on this machine (NotImplementedError)", + "\tfrom -e:2:in `<main>'"] folded diff: - ["Enter PEM pass phrase:"] + ["-e:2:in `setsid': setsid() function is unimplemented on this machine (NotImp + lementedError)", + "\tfrom -e:2:in `<main>'"]

Check failure on line 166 in test/openssl/test_pkey.rb

View workflow job for this annotation

GitHub Actions / windows-latest 3.4

Failure

<["Enter PEM pass phrase:"]> expected but was <["-e:2:in '<main>': setsid() function is unimplemented on this machine (NotImplementedError)", "\tfrom -e:2:in '<main>'"]>. diff: - ["Enter PEM pass phrase:"] + ["-e:2:in '<main>': setsid() function is unimplemented on this machine (NotImplementedError)", + "\tfrom -e:2:in '<main>'"] folded diff: - ["Enter PEM pass phrase:"] + ["-e:2:in '<main>': setsid() function is unimplemented on this machine (NotImp + lementedError)", + "\tfrom -e:2:in '<main>'"]

Check failure on line 166 in test/openssl/test_pkey.rb

View workflow job for this annotation

GitHub Actions / windows-latest head

Failure

<["Enter PEM pass phrase:"]> expected but was <["-e:2:in '<main>': setsid() function is unimplemented on this machine (NotImplementedError)", "\tfrom -e:2:in '<main>'"]>. diff: - ["Enter PEM pass phrase:"] + ["-e:2:in '<main>': setsid() function is unimplemented on this machine (NotImplementedError)", + "\tfrom -e:2:in '<main>'"] folded diff: - ["Enter PEM pass phrase:"] + ["-e:2:in '<main>': setsid() function is unimplemented on this machine (NotImp + lementedError)", + "\tfrom -e:2:in '<main>'"]

Check failure on line 166 in test/openssl/test_pkey.rb

View workflow job for this annotation

GitHub Actions / windows-latest ucrt

Failure

<["Enter PEM pass phrase:"]> expected but was <["-e:2:in '<main>': setsid() function is unimplemented on this machine (NotImplementedError)", "\tfrom -e:2:in '<main>'"]>. diff: - ["Enter PEM pass phrase:"] + ["-e:2:in '<main>': setsid() function is unimplemented on this machine (NotImplementedError)", + "\tfrom -e:2:in '<main>'"] folded diff: - ["Enter PEM pass phrase:"] + ["-e:2:in '<main>': setsid() function is unimplemented on this machine (NotImp + lementedError)", + "\tfrom -e:2:in '<main>'"]

Check failure on line 166 in test/openssl/test_pkey.rb

View workflow job for this annotation

GitHub Actions / windows-latest mswin

Failure

<["Enter PEM pass phrase:"]> expected but was <["-e:2:in '<main>': setsid() function is unimplemented on this machine (NotImplementedError)", "\tfrom -e:2:in '<main>'"]>. diff: - ["Enter PEM pass phrase:"] + ["-e:2:in '<main>': setsid() function is unimplemented on this machine (NotImplementedError)", + "\tfrom -e:2:in '<main>'"] folded diff: - ["Enter PEM pass phrase:"] + ["-e:2:in '<main>': setsid() function is unimplemented on this machine (NotImp + lementedError)", + "\tfrom -e:2:in '<main>'"]

Check failure on line 166 in test/openssl/test_pkey.rb

View workflow job for this annotation

GitHub Actions / windows-latest 3.2

Failure

<["Enter PEM pass phrase:"]> expected but was <["-e:2:in `setsid': setsid() function is unimplemented on this machine (NotImplementedError)", "\tfrom -e:2:in `<main>'"]>. diff: - ["Enter PEM pass phrase:"] + ["-e:2:in `setsid': setsid() function is unimplemented on this machine (NotImplementedError)", + "\tfrom -e:2:in `<main>'"] folded diff: - ["Enter PEM pass phrase:"] + ["-e:2:in `setsid': setsid() function is unimplemented on this machine (NotImp + lementedError)", + "\tfrom -e:2:in `<main>'"]

Check failure on line 166 in test/openssl/test_pkey.rb

View workflow job for this annotation

GitHub Actions / windows-latest 3.3

Failure

<["Enter PEM pass phrase:"]> expected but was <["-e:2:in `setsid': setsid() function is unimplemented on this machine (NotImplementedError)", "\tfrom -e:2:in `<main>'"]>. diff: - ["Enter PEM pass phrase:"] + ["-e:2:in `setsid': setsid() function is unimplemented on this machine (NotImplementedError)", + "\tfrom -e:2:in `<main>'"] folded diff: - ["Enter PEM pass phrase:"] + ["-e:2:in `setsid': setsid() function is unimplemented on this machine (NotImp + lementedError)", + "\tfrom -e:2:in `<main>'"]

Check failure on line 166 in test/openssl/test_pkey.rb

View workflow job for this annotation

GitHub Actions / windows-latest 2.7

Failure

<["Enter PEM pass phrase:"]> expected but was <["-e:2:in `setsid': setsid() function is unimplemented on this machine (NotImplementedError)", "\tfrom -e:2:in `<main>'"]>. diff: - ["Enter PEM pass phrase:"] + ["-e:2:in `setsid': setsid() function is unimplemented on this machine (NotImplementedError)", + "\tfrom -e:2:in `<main>'"] folded diff: - ["Enter PEM pass phrase:"] + ["-e:2:in `setsid': setsid() function is unimplemented on this machine (NotImp + lementedError)", + "\tfrom -e:2:in `<main>'"]
assert_equal(["ok"], stdout)
}

# Incorrect passphrase passed to OpenSSL's prompt
script = <<~"end;"
require "openssl"
Process.setsid
begin
OpenSSL::PKey.read(#{encrypted_pem.dump})
rescue OpenSSL::PKey::PKeyError
puts "ok"
else
puts "expected OpenSSL::PKey::PKeyError"
end
end;
stdin = "incorrect_passphrase\n" * 5
assert_in_out_err([*$:.map { |l| "-I#{l}" }, "-e#{script}"],
stdin) { |stdout, stderr|
assert_equal(1, stderr.count("Enter PEM pass phrase:"))
assert_equal(["ok"], stdout)
}
end

def test_hmac_sign_verify
pkey = OpenSSL::PKey.generate_key("HMAC", { "key" => "abcd" })

Expand Down
Loading