Merge pull request #26 from haydenroche5/pem
Add a pem_to_der function and support for PEM RSA keys.pull/27/head
commit
10ba23046b
|
@ -69,6 +69,7 @@ PWDBASED_ENABLED = 0
|
|||
FIPS_ENABLED = 0
|
||||
FIPS_VERSION = 0
|
||||
ERROR_STRINGS_ENABLED = 1
|
||||
ASN_ENABLED = 1
|
||||
|
||||
# detect native features based on options.h defines
|
||||
if featureDetection:
|
||||
|
@ -91,6 +92,7 @@ if featureDetection:
|
|||
KEYGEN_ENABLED = 1 if '#define WOLFSSL_KEY_GEN' in optionsHeaderStr else 0
|
||||
PWDBASED_ENABLED = 0 if '#define NO_PWDBASED' in optionsHeaderStr else 1
|
||||
ERROR_STRINGS_ENABLED = 0 if '#define NO_ERROR_STRINGS' in optionsHeaderStr else 1
|
||||
ASN_ENABLED = 0 if '#define NO_ASN' in optionsHeaderStr else 1
|
||||
|
||||
if '#define HAVE_FIPS' in optionsHeaderStr:
|
||||
FIPS_ENABLED = 1
|
||||
|
@ -153,6 +155,7 @@ ffibuilder.set_source(
|
|||
int PWDBASED_ENABLED = """ + str(PWDBASED_ENABLED) + """;
|
||||
int FIPS_ENABLED = """ + str(FIPS_ENABLED) + """;
|
||||
int FIPS_VERSION = """ + str(FIPS_VERSION) + """;
|
||||
int ASN_ENABLED = """ + str(ASN_ENABLED) + """;
|
||||
""",
|
||||
include_dirs=[wolfssl_inc_path()],
|
||||
library_dirs=[wolfssl_lib_path()],
|
||||
|
@ -180,6 +183,7 @@ _cdef = """
|
|||
extern int PWDBASED_ENABLED;
|
||||
extern int FIPS_ENABLED;
|
||||
extern int FIPS_VERSION;
|
||||
extern int ASN_ENABLED;
|
||||
|
||||
typedef unsigned char byte;
|
||||
typedef unsigned int word32;
|
||||
|
@ -452,6 +456,28 @@ if PWDBASED_ENABLED:
|
|||
int typeH);
|
||||
"""
|
||||
|
||||
if ASN_ENABLED:
|
||||
_cdef += """
|
||||
static const long PRIVATEKEY_TYPE;
|
||||
static const long PUBLICKEY_TYPE;
|
||||
static const long CERT_TYPE;
|
||||
|
||||
typedef struct DerBuffer {
|
||||
byte* buffer;
|
||||
void* heap;
|
||||
word32 length;
|
||||
int type;
|
||||
int dynType;
|
||||
} DerBuffer;
|
||||
typedef struct { ...; } EncryptedInfo;
|
||||
|
||||
int wc_PemToDer(const unsigned char* buff, long longSz, int type,
|
||||
DerBuffer** pDer, void* heap, EncryptedInfo* info,
|
||||
int* keyFormat);
|
||||
int wc_DerToPemEx(const byte* der, word32 derSz, byte* output, word32 outSz,
|
||||
byte *cipher_info, int type);
|
||||
"""
|
||||
|
||||
ffibuilder.cdef(_cdef)
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
# asn.py
|
||||
#
|
||||
# Copyright (C) 2006-2020 wolfSSL Inc.
|
||||
#
|
||||
# This file is part of wolfSSL. (formerly known as CyaSSL)
|
||||
#
|
||||
# wolfSSL is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# wolfSSL is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
# pylint: disable=no-member,no-name-in-module
|
||||
|
||||
from wolfcrypt._ffi import ffi as _ffi
|
||||
from wolfcrypt._ffi import lib as _lib
|
||||
|
||||
from wolfcrypt.exceptions import WolfCryptError
|
||||
|
||||
|
||||
if _lib.ASN_ENABLED:
|
||||
def pem_to_der(pem, pem_type):
|
||||
der = _ffi.new("DerBuffer**")
|
||||
ret = _lib.wc_PemToDer(pem, len(pem), pem_type, der, _ffi.NULL,
|
||||
_ffi.NULL, _ffi.NULL)
|
||||
if ret != 0:
|
||||
err = "Error converting from PEM to DER. ({})".format(ret)
|
||||
raise WolfCryptError(err)
|
||||
|
||||
return _ffi.buffer(der[0][0].buffer, der[0][0].length)[:]
|
||||
|
||||
def der_to_pem(der, pem_type):
|
||||
pem_length = _lib.wc_DerToPemEx(der, len(der), _ffi.NULL, 0, _ffi.NULL,
|
||||
pem_type)
|
||||
if pem_length <= 0:
|
||||
err = "Error getting required PEM buffer length. ({})".format(pem_length)
|
||||
raise WolfCryptError(err)
|
||||
|
||||
pem = _ffi.new("byte[%d]" % pem_length)
|
||||
pem_length = _lib.wc_DerToPemEx(der, len(der), pem, pem_length,
|
||||
_ffi.NULL, pem_type)
|
||||
if pem_length <= 0:
|
||||
err = "Error converting from DER to PEM. ({})".format(pem_length)
|
||||
raise WolfCryptError(err)
|
||||
|
||||
return _ffi.buffer(pem, pem_length)[:]
|
|
@ -24,6 +24,7 @@ from wolfcrypt._ffi import ffi as _ffi
|
|||
from wolfcrypt._ffi import lib as _lib
|
||||
from wolfcrypt.utils import t2b
|
||||
from wolfcrypt.random import Random
|
||||
from wolfcrypt.asn import pem_to_der
|
||||
|
||||
from wolfcrypt.exceptions import WolfCryptError
|
||||
|
||||
|
@ -359,6 +360,12 @@ if _lib.RSA_ENABLED:
|
|||
raise WolfCryptError("Invalid key error (%d)" %
|
||||
self.output_size)
|
||||
|
||||
if _lib.ASN_ENABLED:
|
||||
@classmethod
|
||||
def from_pem(cls, file):
|
||||
der = pem_to_der(file, _lib.PUBLICKEY_TYPE)
|
||||
return cls(der)
|
||||
|
||||
def encrypt(self, plaintext):
|
||||
"""
|
||||
Encrypts **plaintext**, using the public key data in the
|
||||
|
@ -455,6 +462,12 @@ if _lib.RSA_ENABLED:
|
|||
raise WolfCryptError("Invalid key size error (%d)" %
|
||||
self.output_size)
|
||||
|
||||
if _lib.ASN_ENABLED:
|
||||
@classmethod
|
||||
def from_pem(cls, file):
|
||||
der = pem_to_der(file, _lib.PRIVATEKEY_TYPE)
|
||||
return cls(der)
|
||||
|
||||
if _lib.KEYGEN_ENABLED:
|
||||
def encode_key(self):
|
||||
"""
|
||||
|
|
|
@ -31,7 +31,7 @@ _BINARY_TYPE = bytes if _PY3 else str
|
|||
|
||||
def t2b(string):
|
||||
"""
|
||||
Converts text to bynary.
|
||||
Converts text to binary.
|
||||
"""
|
||||
if isinstance(string, _BINARY_TYPE):
|
||||
return string
|
||||
|
|
Binary file not shown.
|
@ -0,0 +1,29 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIE3TCCA8WgAwIBAgIBATANBgkqhkiG9w0BAQsFADCBlDELMAkGA1UEBhMCVVMx
|
||||
EDAOBgNVBAgMB01vbnRhbmExEDAOBgNVBAcMB0JvemVtYW4xETAPBgNVBAoMCFNh
|
||||
d3Rvb3RoMRMwEQYDVQQLDApDb25zdWx0aW5nMRgwFgYDVQQDDA93d3cud29sZnNz
|
||||
bC5jb20xHzAdBgkqhkiG9w0BCQEWEGluZm9Ad29sZnNzbC5jb20wHhcNMjEwMjEw
|
||||
MTk0OTUzWhcNMjMxMTA3MTk0OTUzWjCBkDELMAkGA1UEBhMCVVMxEDAOBgNVBAgM
|
||||
B01vbnRhbmExEDAOBgNVBAcMB0JvemVtYW4xEDAOBgNVBAoMB3dvbGZTU0wxEDAO
|
||||
BgNVBAsMB1N1cHBvcnQxGDAWBgNVBAMMD3d3dy53b2xmc3NsLmNvbTEfMB0GCSqG
|
||||
SIb3DQEJARYQaW5mb0B3b2xmc3NsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEP
|
||||
ADCCAQoCggEBAMCVCOFXQfJxbbfSRUEnAWXGRa7yvCQwuJXOL07W9hyIvHyf+6hn
|
||||
f/5cnFF194rKB+c1L4/hvXvAL3yrZKgX/Mpde7rgIeVyLm8uhtiVc9qsG1O5Xz/X
|
||||
GQ0lT+FjY1GLC2Q/rUO4pRxcNLOuAKBjxfZ/C1loeHOmjBipAm2vwxkBLrgQ48bM
|
||||
QLRpo0YzaYduxLsXpvPo3a1zvHsvIbX9ZlEMvVSz4W1fHLwjc9EJA4kU0hC5ZMMq
|
||||
0KGWSrzh1Bpbx6DAwWN4D0Q3MDKWgDIjlaF3uhPSl3PiXSXJag3DOWCktLBpQkIJ
|
||||
6dgIvDMgs1gip6rrxOHmYYPF0pbf2dBPrdcCAwEAAaOCATowggE2MB0GA1UdDgQW
|
||||
BBSzETLJkpiE4sn40DtuA0LKHw6OPDCByQYDVR0jBIHBMIG+gBQnjmcRdMMmHT/t
|
||||
M2OzpNgdMOXo1aGBmqSBlzCBlDELMAkGA1UEBhMCVVMxEDAOBgNVBAgMB01vbnRh
|
||||
bmExEDAOBgNVBAcMB0JvemVtYW4xETAPBgNVBAoMCFNhd3Rvb3RoMRMwEQYDVQQL
|
||||
DApDb25zdWx0aW5nMRgwFgYDVQQDDA93d3cud29sZnNzbC5jb20xHzAdBgkqhkiG
|
||||
9w0BCQEWEGluZm9Ad29sZnNzbC5jb22CCQCq0z+sGAo3TTAMBgNVHRMEBTADAQH/
|
||||
MBwGA1UdEQQVMBOCC2V4YW1wbGUuY29thwR/AAABMB0GA1UdJQQWMBQGCCsGAQUF
|
||||
BwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAGw2mRJMNDgw1KCZAMdLr
|
||||
JkxHWxn7rf469TA6KNeqaaQV5yZutzNWrI80PfMhL1NYkdA+tDlIv5MRdDbTh0nD
|
||||
NA0wMKv0TCcZ1cQMrUm9kfjansgtKqzidY6qCNm/Zf+jsU/wYG9NlcQGf69maiM7
|
||||
OqRhtmzKvuGwd/Psg9WMHYV/jXTI7B5J7FdKzP3iOj5UUK5nzRewZ6VTf8MOPqdY
|
||||
6N/VDPJk860ScOO5QrwIYHbVDKUxd1DgyPM6PUXPMnXvEN217W7SLVeClTi8fVTE
|
||||
hF77foP18S2cmKxz46fSAjDWHwYe0Nw6rPTCwr5yQJrqzzUhO1Zt4VLygNc1g5cH
|
||||
zA==
|
||||
-----END CERTIFICATE-----
|
Binary file not shown.
|
@ -0,0 +1,27 @@
|
|||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpQIBAAKCAQEAwJUI4VdB8nFtt9JFQScBZcZFrvK8JDC4lc4vTtb2HIi8fJ/7
|
||||
qGd//lycUXX3isoH5zUvj+G9e8AvfKtkqBf8yl17uuAh5XIuby6G2JVz2qwbU7lf
|
||||
P9cZDSVP4WNjUYsLZD+tQ7ilHFw0s64AoGPF9n8LWWh4c6aMGKkCba/DGQEuuBDj
|
||||
xsxAtGmjRjNph27Euxem8+jdrXO8ey8htf1mUQy9VLPhbV8cvCNz0QkDiRTSELlk
|
||||
wyrQoZZKvOHUGlvHoMDBY3gPRDcwMpaAMiOVoXe6E9KXc+JdJclqDcM5YKS0sGlC
|
||||
Qgnp2Ai8MyCzWCKnquvE4eZhg8XSlt/Z0E+t1wIDAQABAoIBAQCa0DQPUmIFUAHv
|
||||
n+1kbsLE2hryhNeSEEiSxOlq64t1bMZ5OPLJckqGZFSVd8vDmp231B2kAMieTuTd
|
||||
x7pnFsF0vKnWlI8rMBr77d8hBSPZSjm9mGtlmrjcxH3upkMVLj2+HSJgKnMw1T7Y
|
||||
oqyGQy7E9WReP4l1DxHYUSVOn9iqo85gs+KK2X4b8GTKmlsFC1uqy+XjP24yIgXz
|
||||
0PrvdFKB4l90073/MYNFdfpjepcu1rYZxpIm5CgGUFAOeC6peA0Ul7QS2DFAq6EB
|
||||
QcIw+AdfFuRhd9Jg8p+N6PS662PeKpeB70xs5lU0USsoNPRTHMRYCj+7r7X3SoVD
|
||||
LTzxWFiBAoGBAPIsVHY5I2PJEDK3k62vvhl1loFk5rW4iUJB0W3QHBv4G6xpyzY8
|
||||
ZH3c9Bm4w2CxV0hfUk9ZOlV/MsAZQ1A/rs5vF/MOn0DKTq0VO8l56cBZOHNwnAp8
|
||||
yTpIMqfYSXUKhcLC/RVz2pkJKmmanwpxv7AEpox6Wm9IWlQ7xrFTF9/nAoGBAMuT
|
||||
3ncVXbdcXHzYkKmYLdZpDmOzo9ymzItqpKISjI57SCyySzfcBhh96v52odSh6T8N
|
||||
zRtfr1+elltbD6F8r7ObkNtXczrtsCNErkFPHwdCEyNMy/r0FKTV9542fFufqDzB
|
||||
hV900jkt/9CE3/uzIHoumxeu5roLrl9TpFLtG8SRAoGBAOyY2rvV/vlSSn0CVUlv
|
||||
VW5SL4SjK7OGYrNU0mNS2uOIdqDvixWl0xgUcndex6MEH54ZYrUbG57D8rUy+UzB
|
||||
qusMJn3UX0pRXKRFBnBEp1bA1CIUdp7YY1CJkNPiv4GVkjFBhzkaQwsYpVMfORpf
|
||||
H0O8h2rfbtMiAP4imHBOGhkpAoGBAIpBVihRnl/Ungs7mKNU8mxW1KrpaTOFJAza
|
||||
1AwtxL9PAmk4fNTm3Ezt1xYRwz4A58MmwFEC3rt1nG9WnHrzju/PisUr0toGakTJ
|
||||
c/5umYf4W77xfOZltU9s8MnF/xbKixsX4lg9ojerAby/QM5TjI7t7+5ZneBj5nxe
|
||||
9Y5L8TvBAoGATUX5QIzFW/QqGoq08hysa+kMVja3TnKW1eWK0uL/8fEYEz2GCbjY
|
||||
dqfJHHFSlDBD4PF4dP1hG0wJzOZoKnGtHN9DvFbbpaS+NXCkXs9P/ABVmTo9I89n
|
||||
WvUi+LUp0EQR6zUuRr79jhiyX6i/GTKh9dwD5nyaHwx8qbAOITc78bA=
|
||||
-----END RSA PRIVATE KEY-----
|
|
@ -0,0 +1,9 @@
|
|||
-----BEGIN RSA PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwJUI4VdB8nFtt9JFQScB
|
||||
ZcZFrvK8JDC4lc4vTtb2HIi8fJ/7qGd//lycUXX3isoH5zUvj+G9e8AvfKtkqBf8
|
||||
yl17uuAh5XIuby6G2JVz2qwbU7lfP9cZDSVP4WNjUYsLZD+tQ7ilHFw0s64AoGPF
|
||||
9n8LWWh4c6aMGKkCba/DGQEuuBDjxsxAtGmjRjNph27Euxem8+jdrXO8ey8htf1m
|
||||
UQy9VLPhbV8cvCNz0QkDiRTSELlkwyrQoZZKvOHUGlvHoMDBY3gPRDcwMpaAMiOV
|
||||
oXe6E9KXc+JdJclqDcM5YKS0sGlCQgnp2Ai8MyCzWCKnquvE4eZhg8XSlt/Z0E+t
|
||||
1wIDAQAB
|
||||
-----END RSA PUBLIC KEY-----
|
|
@ -0,0 +1,47 @@
|
|||
from collections import namedtuple
|
||||
import pytest
|
||||
import os
|
||||
from wolfcrypt._ffi import lib as _lib
|
||||
from wolfcrypt.utils import h2b
|
||||
|
||||
if _lib.ASN_ENABLED:
|
||||
from wolfcrypt.asn import pem_to_der, der_to_pem
|
||||
if _lib.SHA256_ENABLED:
|
||||
from wolfcrypt.hashes import Sha256
|
||||
if _lib.RSA_ENABLED:
|
||||
from wolfcrypt.ciphers import RsaPrivate, RsaPublic
|
||||
|
||||
certs_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "certs")
|
||||
|
||||
@pytest.fixture
|
||||
def pem_der_conversion_vectors():
|
||||
TestVector = namedtuple("TestVector", "pem der type")
|
||||
TestVector.__new__.__defaults__ = (None,) * len(TestVector._fields)
|
||||
|
||||
vectors = []
|
||||
|
||||
if _lib.ASN_ENABLED:
|
||||
files = [
|
||||
("server-key.pem", "server-key.der", _lib.PRIVATEKEY_TYPE),
|
||||
("server-cert.pem", "server-cert.der", _lib.CERT_TYPE),
|
||||
]
|
||||
for f in files:
|
||||
pem_path = os.path.join(certs_dir, f[0])
|
||||
with open(pem_path, "rb") as pem_handle:
|
||||
pem = pem_handle.read()
|
||||
|
||||
der_path = os.path.join(certs_dir, f[1])
|
||||
with open(der_path, "rb") as der_handle:
|
||||
der = der_handle.read()
|
||||
|
||||
vectors.append(TestVector(pem=pem, der=der, type=f[2]))
|
||||
|
||||
return vectors
|
||||
|
||||
def test_pem_der_conversion(pem_der_conversion_vectors):
|
||||
for vector in pem_der_conversion_vectors:
|
||||
computed_der = pem_to_der(vector.pem, vector.type)
|
||||
assert computed_der == vector.der
|
||||
|
||||
computed_pem = der_to_pem(vector.der, vector.type)
|
||||
assert computed_pem == vector.pem
|
|
@ -25,6 +25,9 @@ import pytest
|
|||
from wolfcrypt._ffi import ffi as _ffi
|
||||
from wolfcrypt._ffi import lib as _lib
|
||||
from wolfcrypt.utils import t2b, h2b
|
||||
import os
|
||||
|
||||
certs_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "certs")
|
||||
|
||||
if _lib.DES3_ENABLED:
|
||||
from wolfcrypt.ciphers import Des3
|
||||
|
@ -54,7 +57,8 @@ from wolfcrypt.ciphers import (
|
|||
|
||||
@pytest.fixture
|
||||
def vectors():
|
||||
TestVector = namedtuple("TestVector", "key iv plaintext ciphertext raw_key pkcs8_key")
|
||||
TestVector = namedtuple("TestVector", """key iv plaintext ciphertext raw_key
|
||||
pkcs8_key pem""")
|
||||
TestVector.__new__.__defaults__ = (None,) * len(TestVector._fields)
|
||||
|
||||
# test vector dictionary
|
||||
|
@ -88,7 +92,8 @@ def vectors():
|
|||
"905F3ED9E4D5DF94CAC1A9D719DA86C9E84DC4613682FEABAD7E7725BB8D"
|
||||
"11A5BC623AA838CC39A20466B4F7F7F3AADA4D020EBB5E8D6948DC77C928"
|
||||
"0E22E96BA426BA4CE8C1FD4A6F2B1FEF8AAEF69062E5641EEB2B3C67C8DC"
|
||||
"2700F6916865A90203010001")
|
||||
"2700F6916865A90203010001"),
|
||||
pem=os.path.join(certs_dir, "server-keyPub.pem")
|
||||
)
|
||||
vectorArray[RsaPrivate]=TestVector(
|
||||
key=h2b(
|
||||
|
@ -153,7 +158,8 @@ def vectors():
|
|||
"30bab7488c48140ef49f7e779743e1b4"
|
||||
"19353123759c3b44ad691256ee006164"
|
||||
"1666d37c742b15b4a2febf086b1a5d3f"
|
||||
"9012b105863129dbd9e2")
|
||||
"9012b105863129dbd9e2"),
|
||||
pem=os.path.join(certs_dir, "server-key.pem")
|
||||
)
|
||||
|
||||
if _lib.ECC_ENABLED:
|
||||
|
@ -323,6 +329,18 @@ if _lib.RSA_ENABLED:
|
|||
def rsa_public(vectors):
|
||||
return RsaPublic(vectors[RsaPublic].key)
|
||||
|
||||
@pytest.fixture
|
||||
def rsa_private_pem(vectors):
|
||||
with open(vectors[RsaPrivate].pem, "rb") as f:
|
||||
pem = f.read()
|
||||
return RsaPrivate.from_pem(pem)
|
||||
|
||||
@pytest.fixture
|
||||
def rsa_public_pem(vectors):
|
||||
with open(vectors[RsaPublic].pem, "rb") as f:
|
||||
pem = f.read()
|
||||
return RsaPublic.from_pem(pem)
|
||||
|
||||
|
||||
def test_new_rsa_raises(vectors):
|
||||
with pytest.raises(WolfCryptError):
|
||||
|
@ -385,6 +403,22 @@ if _lib.RSA_ENABLED:
|
|||
assert 1024 / 8 == len(signature) == rsa_private.output_size
|
||||
assert plaintext == rsa_private.verify(signature)
|
||||
|
||||
def test_rsa_sign_verify_pem(rsa_private_pem, rsa_public_pem):
|
||||
plaintext = t2b("Everyone gets Friday off.")
|
||||
|
||||
# normal usage, sign with private, verify with public
|
||||
signature = rsa_private_pem.sign(plaintext)
|
||||
|
||||
assert 256 == len(signature) == rsa_private_pem.output_size
|
||||
assert plaintext == rsa_public_pem.verify(signature)
|
||||
|
||||
# private object holds both private and public info, so it can also verify
|
||||
# using the known public key.
|
||||
signature = rsa_private_pem.sign(plaintext)
|
||||
|
||||
assert 256 == len(signature) == rsa_private_pem.output_size
|
||||
assert plaintext == rsa_private_pem.verify(signature)
|
||||
|
||||
def test_rsa_pkcs8_sign_verify(rsa_private_pkcs8, rsa_public):
|
||||
plaintext = t2b("Everyone gets Friday off.")
|
||||
|
||||
|
|
Loading…
Reference in New Issue