mirror of
https://github.com/libp2p/go-openssl.git
synced 2024-12-25 23:30:06 +08:00
Ed25519 key support (#103)
* ed gen, sign, verify works. tested25519 fails * Ignore some unit tests in ED since it relies on GoLang lib to support Ed keys * Cleanup sign and verify operations * Cleanup and prettify * cleanups * Conditional X_EVP_PKEY_ED25519 and X_EVP_Digest{Sign|Verify}[Init] based on openssl version.
This commit is contained in:
parent
3b86b42896
commit
8ea58d1789
1
AUTHORS
1
AUTHORS
@ -21,3 +21,4 @@ Stephen Gallagher <sgallagh@redhat.com>
|
||||
Viacheslav Biriukov <v.v.biriukov@gmail.com>
|
||||
Zack Owens <zowens2009@gmail.com>
|
||||
Ramesh Rayaprolu <rarayapr@cisco.com>
|
||||
Paras Shah <parasssh@gmail.com>
|
||||
|
131
key.go
131
key.go
@ -50,6 +50,10 @@ const (
|
||||
KeyTypeCMAC = NID_cmac
|
||||
KeyTypeTLS1PRF = NID_tls1_prf
|
||||
KeyTypeHKDF = NID_hkdf
|
||||
KeyTypeX25519 = NID_X25519
|
||||
KeyTypeX448 = NID_X448
|
||||
KeyTypeED25519 = NID_ED25519
|
||||
KeyTypeED448 = NID_ED448
|
||||
)
|
||||
|
||||
type PublicKey interface {
|
||||
@ -110,45 +114,94 @@ func (key *pKey) BaseType() NID {
|
||||
}
|
||||
|
||||
func (key *pKey) SignPKCS1v15(method Method, data []byte) ([]byte, error) {
|
||||
|
||||
ctx := C.X_EVP_MD_CTX_new()
|
||||
defer C.X_EVP_MD_CTX_free(ctx)
|
||||
|
||||
if 1 != C.X_EVP_SignInit(ctx, method) {
|
||||
return nil, errors.New("signpkcs1v15: failed to init signature")
|
||||
}
|
||||
if len(data) > 0 {
|
||||
if 1 != C.X_EVP_SignUpdate(
|
||||
ctx, unsafe.Pointer(&data[0]), C.uint(len(data))) {
|
||||
return nil, errors.New("signpkcs1v15: failed to update signature")
|
||||
if key.KeyType() == KeyTypeED25519 {
|
||||
// do ED specific one-shot sign
|
||||
|
||||
if method != nil || len(data) == 0 {
|
||||
return nil, errors.New("signpkcs1v15: 0-length data or non-null digest")
|
||||
}
|
||||
|
||||
if 1 != C.X_EVP_DigestSignInit(ctx, nil, nil, nil, key.key) {
|
||||
return nil, errors.New("signpkcs1v15: failed to init signature")
|
||||
}
|
||||
|
||||
// evp signatures are 64 bytes
|
||||
sig := make([]byte, 64, 64)
|
||||
var sigblen C.ulong = 64
|
||||
if 1 != C.X_EVP_DigestSign(ctx,
|
||||
((*C.uchar)(unsafe.Pointer(&sig[0]))),
|
||||
&sigblen,
|
||||
(*C.uchar)(unsafe.Pointer(&data[0])),
|
||||
C.ulong(len(data))) {
|
||||
return nil, errors.New("signpkcs1v15: failed to do one-shot signature")
|
||||
}
|
||||
|
||||
return sig[:sigblen], nil
|
||||
} else {
|
||||
if 1 != C.X_EVP_SignInit(ctx, method) {
|
||||
return nil, errors.New("signpkcs1v15: failed to init signature")
|
||||
}
|
||||
if len(data) > 0 {
|
||||
if 1 != C.X_EVP_SignUpdate(
|
||||
ctx, unsafe.Pointer(&data[0]), C.uint(len(data))) {
|
||||
return nil, errors.New("signpkcs1v15: failed to update signature")
|
||||
}
|
||||
}
|
||||
sig := make([]byte, C.X_EVP_PKEY_size(key.key))
|
||||
var sigblen C.uint
|
||||
if 1 != C.X_EVP_SignFinal(ctx,
|
||||
((*C.uchar)(unsafe.Pointer(&sig[0]))), &sigblen, key.key) {
|
||||
return nil, errors.New("signpkcs1v15: failed to finalize signature")
|
||||
}
|
||||
return sig[:sigblen], nil
|
||||
}
|
||||
sig := make([]byte, C.X_EVP_PKEY_size(key.key))
|
||||
var sigblen C.uint
|
||||
if 1 != C.X_EVP_SignFinal(ctx,
|
||||
((*C.uchar)(unsafe.Pointer(&sig[0]))), &sigblen, key.key) {
|
||||
return nil, errors.New("signpkcs1v15: failed to finalize signature")
|
||||
}
|
||||
return sig[:sigblen], nil
|
||||
}
|
||||
|
||||
func (key *pKey) VerifyPKCS1v15(method Method, data, sig []byte) error {
|
||||
ctx := C.X_EVP_MD_CTX_new()
|
||||
defer C.X_EVP_MD_CTX_free(ctx)
|
||||
|
||||
if 1 != C.X_EVP_VerifyInit(ctx, method) {
|
||||
return errors.New("verifypkcs1v15: failed to init verify")
|
||||
}
|
||||
if len(data) > 0 {
|
||||
if 1 != C.X_EVP_VerifyUpdate(
|
||||
ctx, unsafe.Pointer(&data[0]), C.uint(len(data))) {
|
||||
return errors.New("verifypkcs1v15: failed to update verify")
|
||||
if key.KeyType() == KeyTypeED25519 {
|
||||
// do ED specific one-shot sign
|
||||
|
||||
if method != nil || len(data) == 0 || len(sig) == 0 {
|
||||
return errors.New("verifypkcs1v15: 0-length data or sig or non-null digest")
|
||||
}
|
||||
|
||||
if 1 != C.X_EVP_DigestVerifyInit(ctx, nil, nil, nil, key.key) {
|
||||
return errors.New("verifypkcs1v15: failed to init verify")
|
||||
}
|
||||
|
||||
if 1 != C.X_EVP_DigestVerify(ctx,
|
||||
((*C.uchar)(unsafe.Pointer(&sig[0]))),
|
||||
C.ulong(len(sig)),
|
||||
(*C.uchar)(unsafe.Pointer(&data[0])),
|
||||
C.ulong(len(data))) {
|
||||
return errors.New("verifypkcs1v15: failed to do one-shot verify")
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
} else {
|
||||
if 1 != C.X_EVP_VerifyInit(ctx, method) {
|
||||
return errors.New("verifypkcs1v15: failed to init verify")
|
||||
}
|
||||
if len(data) > 0 {
|
||||
if 1 != C.X_EVP_VerifyUpdate(
|
||||
ctx, unsafe.Pointer(&data[0]), C.uint(len(data))) {
|
||||
return errors.New("verifypkcs1v15: failed to update verify")
|
||||
}
|
||||
}
|
||||
if 1 != C.X_EVP_VerifyFinal(ctx,
|
||||
((*C.uchar)(unsafe.Pointer(&sig[0]))), C.uint(len(sig)), key.key) {
|
||||
return errors.New("verifypkcs1v15: failed to finalize verify")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if 1 != C.X_EVP_VerifyFinal(ctx,
|
||||
((*C.uchar)(unsafe.Pointer(&sig[0]))), C.uint(len(sig)), key.key) {
|
||||
return errors.New("verifypkcs1v15: failed to finalize verify")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (key *pKey) MarshalPKCS1PrivateKeyPEM() (pem_block []byte,
|
||||
@ -420,3 +473,29 @@ func GenerateECKey(curve EllipticCurve) (PrivateKey, error) {
|
||||
})
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// GenerateED25519Key generates a Ed25519 key
|
||||
func GenerateED25519Key() (PrivateKey, error) {
|
||||
|
||||
// Key context
|
||||
keyCtx := C.EVP_PKEY_CTX_new_id(C.X_EVP_PKEY_ED25519, nil)
|
||||
if keyCtx == nil {
|
||||
return nil, errors.New("failed creating EC parameter generation context")
|
||||
}
|
||||
defer C.EVP_PKEY_CTX_free(keyCtx)
|
||||
|
||||
// Generate the key
|
||||
var privKey *C.EVP_PKEY
|
||||
if int(C.EVP_PKEY_keygen_init(keyCtx)) != 1 {
|
||||
return nil, errors.New("failed initializing ED25519 key generation context")
|
||||
}
|
||||
if int(C.EVP_PKEY_keygen(keyCtx, &privKey)) != 1 {
|
||||
return nil, errors.New("failed generating ED25519 private key")
|
||||
}
|
||||
|
||||
p := &pKey{key: privKey}
|
||||
runtime.SetFinalizer(p, func(p *pKey) {
|
||||
C.X_EVP_PKEY_free(p.key)
|
||||
})
|
||||
return p, nil
|
||||
}
|
||||
|
106
key_test.go
106
key_test.go
@ -174,6 +174,21 @@ func TestGenerateEC(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateEd25519(t *testing.T) {
|
||||
key, err := GenerateED25519Key()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err = key.MarshalPKIXPublicKeyPEM()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err = key.MarshalPKCS1PrivateKeyPEM()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSign(t *testing.T) {
|
||||
key, _ := GenerateRSAKey(1024)
|
||||
data := []byte("the quick brown fox jumps over the lazy dog")
|
||||
@ -237,6 +252,30 @@ func TestSignEC(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestSignED25519(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
key, err := GenerateED25519Key()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
data := []byte("the quick brown fox jumps over the lazy dog")
|
||||
|
||||
t.Run("new", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
sig, err := key.SignPKCS1v15(nil, data)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = key.VerifyPKCS1v15(nil, data, sig)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestMarshalEC(t *testing.T) {
|
||||
key, err := LoadPrivateKeyFromPEM(prime256v1KeyBytes)
|
||||
if err != nil {
|
||||
@ -353,3 +392,70 @@ func TestMarshalEC(t *testing.T) {
|
||||
t.Fatal("invalid public key der bytes")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarshalEd25519(t *testing.T) {
|
||||
key, err := LoadPrivateKeyFromPEM(ed25519KeyBytes)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
cert, err := LoadCertificateFromPEM(ed25519CertBytes)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
privateBlock, _ := pem_pkg.Decode(ed25519KeyBytes)
|
||||
key, err = LoadPrivateKeyFromDER(privateBlock.Bytes)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
pem, err := cert.MarshalPEM()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Equal(pem, ed25519CertBytes) {
|
||||
ioutil.WriteFile("generated", pem, 0644)
|
||||
ioutil.WriteFile("hardcoded", ed25519CertBytes, 0644)
|
||||
t.Fatal("invalid cert pem bytes")
|
||||
}
|
||||
|
||||
pem, err = key.MarshalPKCS1PrivateKeyPEM()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
der, err := key.MarshalPKCS1PrivateKeyDER()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
der, err = key.MarshalPKIXPublicKeyDER()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
pem, err = key.MarshalPKIXPublicKeyPEM()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
loaded_pubkey_from_pem, err := LoadPublicKeyFromPEM(pem)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
loaded_pubkey_from_der, err := LoadPublicKeyFromDER(der)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = loaded_pubkey_from_pem.MarshalPKIXPublicKeyDER()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = loaded_pubkey_from_der.MarshalPKIXPublicKeyDER()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
4
nid.go
4
nid.go
@ -203,4 +203,8 @@ const (
|
||||
NID_dhpublicnumber NID = 920
|
||||
NID_tls1_prf NID = 1021
|
||||
NID_hkdf NID = 1036
|
||||
NID_X25519 NID = 1034
|
||||
NID_X448 NID = 1035
|
||||
NID_ED25519 NID = 1087
|
||||
NID_ED448 NID = 1088
|
||||
)
|
||||
|
53
shim.c
53
shim.c
@ -38,6 +38,59 @@ static int go_write_bio_puts(BIO *b, const char *str) {
|
||||
return go_write_bio_write(b, (char*)str, (int)strlen(str));
|
||||
}
|
||||
|
||||
/*
|
||||
************************************************
|
||||
* v1.1.1 and later implementation
|
||||
************************************************
|
||||
*/
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x1010100fL
|
||||
int X_EVP_PKEY_ED25519 = EVP_PKEY_ED25519;
|
||||
|
||||
int X_EVP_DigestSignInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
|
||||
const EVP_MD *type, ENGINE *e, EVP_PKEY *pkey){
|
||||
return EVP_DigestSignInit(ctx, pctx, type, e, pkey);
|
||||
}
|
||||
|
||||
int X_EVP_DigestSign(EVP_MD_CTX *ctx, unsigned char *sigret,
|
||||
size_t *siglen, const unsigned char *tbs, size_t tbslen) {
|
||||
return EVP_DigestSign(ctx, sigret, siglen, tbs, tbslen);
|
||||
}
|
||||
|
||||
|
||||
int X_EVP_DigestVerifyInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
|
||||
const EVP_MD *type, ENGINE *e, EVP_PKEY *pkey){
|
||||
return EVP_DigestVerifyInit(ctx, pctx, type, e, pkey);
|
||||
}
|
||||
|
||||
int X_EVP_DigestVerify(EVP_MD_CTX *ctx, const unsigned char *sigret,
|
||||
size_t siglen, const unsigned char *tbs, size_t tbslen){
|
||||
return EVP_DigestVerify(ctx, sigret, siglen, tbs, tbslen);
|
||||
}
|
||||
#else
|
||||
int X_EVP_PKEY_ED25519 = EVP_PKEY_NONE;
|
||||
|
||||
int X_EVP_DigestSignInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
|
||||
const EVP_MD *type, ENGINE *e, EVP_PKEY *pkey){
|
||||
return 0;
|
||||
}
|
||||
|
||||
int X_EVP_DigestSign(EVP_MD_CTX *ctx, unsigned char *sigret,
|
||||
size_t *siglen, const unsigned char *tbs, size_t tbslen) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int X_EVP_DigestVerifyInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
|
||||
const EVP_MD *type, ENGINE *e, EVP_PKEY *pkey){
|
||||
return 0;
|
||||
}
|
||||
|
||||
int X_EVP_DigestVerify(EVP_MD_CTX *ctx, const unsigned char *sigret,
|
||||
size_t siglen, const unsigned char *tbs, size_t tbslen){
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
************************************************
|
||||
* v1.1.X and later implementation
|
||||
|
5
shim.h
5
shim.h
@ -102,6 +102,7 @@ extern BIO *X_BIO_new_write_bio();
|
||||
extern BIO *X_BIO_new_read_bio();
|
||||
|
||||
/* EVP methods */
|
||||
extern int X_EVP_PKEY_ED25519;
|
||||
extern const EVP_MD *X_EVP_get_digestbyname(const char *name);
|
||||
extern EVP_MD_CTX *X_EVP_MD_CTX_new();
|
||||
extern void X_EVP_MD_CTX_free(EVP_MD_CTX *ctx);
|
||||
@ -122,6 +123,8 @@ extern int X_EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *d, size_t cnt);
|
||||
extern int X_EVP_DigestFinal_ex(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *s);
|
||||
extern int X_EVP_SignInit(EVP_MD_CTX *ctx, const EVP_MD *type);
|
||||
extern int X_EVP_SignUpdate(EVP_MD_CTX *ctx, const void *d, unsigned int cnt);
|
||||
extern int X_EVP_DigestSignInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, const EVP_MD *type, ENGINE *e, EVP_PKEY *pkey);
|
||||
extern int X_EVP_DigestSign(EVP_MD_CTX *ctx, unsigned char *sigret, size_t *siglen, const unsigned char *tbs, size_t tbslen);
|
||||
extern EVP_PKEY *X_EVP_PKEY_new(void);
|
||||
extern void X_EVP_PKEY_free(EVP_PKEY *pkey);
|
||||
extern int X_EVP_PKEY_size(EVP_PKEY *pkey);
|
||||
@ -132,6 +135,8 @@ extern int X_EVP_SignFinal(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *s,
|
||||
extern int X_EVP_VerifyInit(EVP_MD_CTX *ctx, const EVP_MD *type);
|
||||
extern int X_EVP_VerifyUpdate(EVP_MD_CTX *ctx, const void *d, unsigned int cnt);
|
||||
extern int X_EVP_VerifyFinal(EVP_MD_CTX *ctx, const unsigned char *sigbuf, unsigned int siglen, EVP_PKEY *pkey);
|
||||
extern int X_EVP_DigestVerifyInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, const EVP_MD *type, ENGINE *e, EVP_PKEY *pkey);
|
||||
extern int X_EVP_DigestVerify(EVP_MD_CTX *ctx, const unsigned char *sigret, size_t siglen, const unsigned char *tbs, size_t tbslen);
|
||||
extern int X_EVP_CIPHER_block_size(EVP_CIPHER *c);
|
||||
extern int X_EVP_CIPHER_key_length(EVP_CIPHER *c);
|
||||
extern int X_EVP_CIPHER_iv_length(EVP_CIPHER *c);
|
||||
|
14
ssl_test.go
14
ssl_test.go
@ -103,6 +103,20 @@ FhlGM1wzvusyGrm26Vrbqm4wDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNJ
|
||||
ADBGAiEA6PWNjm4B6zs3Wcha9qyDdfo1ILhHfk9rZEAGrnfyc2UCIQD1IDVJUkI4
|
||||
J/QVoOtP5DOdRPs/3XFy0Bk0qH+Uj5D7LQ==
|
||||
-----END CERTIFICATE-----
|
||||
`)
|
||||
ed25519CertBytes = []byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIBIzCB1gIUd0UUPX+qHrSKSVN9V/A3F1Eeti4wBQYDK2VwMDYxCzAJBgNVBAYT
|
||||
AnVzMQ0wCwYDVQQKDARDU0NPMRgwFgYDVQQDDA9lZDI1NTE5X3Jvb3RfY2EwHhcN
|
||||
MTgwODE3MDMzNzQ4WhcNMjgwODE0MDMzNzQ4WjAzMQswCQYDVQQGEwJ1czENMAsG
|
||||
A1UECgwEQ1NDTzEVMBMGA1UEAwwMZWQyNTUxOV9sZWFmMCowBQYDK2VwAyEAKZZJ
|
||||
zzlBcpjdbvzV0BRoaSiJKxbU6GnFeAELA0cHWR0wBQYDK2VwA0EAbfUJ7L7v3GDq
|
||||
Gv7R90wQ/OKAc+o0q9eOrD6KRYDBhvlnMKqTMRVucnHXfrd5Rhmf4yHTvFTOhwmO
|
||||
t/hpmISAAA==
|
||||
-----END CERTIFICATE-----
|
||||
`)
|
||||
ed25519KeyBytes = []byte(`-----BEGIN PRIVATE KEY-----
|
||||
MC4CAQAwBQYDK2VwBCIEIL3QVwyuusKuLgZwZn356UHk9u1REGHbNTLtFMPKNQSb
|
||||
-----END PRIVATE KEY-----
|
||||
`)
|
||||
)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user