From e3f9a33771277a44c7e4a6f8fd9a27543026ef69 Mon Sep 17 00:00:00 2001 From: Quim Muntal Date: Thu, 12 May 2022 18:50:12 +0000 Subject: [PATCH 1/4] don't depend on big.Int nor asn1 --- openssl/bbig/big.go | 110 ++++++++++++++++++++++++++++++++++++++++++ openssl/ecdsa.go | 39 ++------------- openssl/ecdsa_test.go | 16 +++--- openssl/openssl.go | 23 +++++---- openssl/rsa.go | 23 +++++---- openssl/rsa_test.go | 65 +++++++++++++++---------- 6 files changed, 187 insertions(+), 89 deletions(-) create mode 100644 openssl/bbig/big.go diff --git a/openssl/bbig/big.go b/openssl/bbig/big.go new file mode 100644 index 0000000..d3bed4e --- /dev/null +++ b/openssl/bbig/big.go @@ -0,0 +1,110 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This is a mirror of crypto/internal/boring/bbig/big.go. + +package bbig + +import ( + "encoding/asn1" + "math/big" + "unsafe" + + "github.com/microsoft/go-crypto-openssl/openssl" +) + +func Enc(b *big.Int) openssl.BigInt { + if b == nil { + return nil + } + x := b.Bits() + if len(x) == 0 { + return openssl.BigInt{} + } + // TODO: Use unsafe.Slice((*uint)(&x[0]), len(x)) once go1.16 is no longer supported. + return (*[1 << 30]uint)(unsafe.Pointer(&x[0]))[:len(x)] +} + +func Dec(b openssl.BigInt) *big.Int { + if b == nil { + return nil + } + if len(b) == 0 { + return new(big.Int) + } + // TODO: Use unsafe.Slice((*uint)(&b[0]), len(b)) once go1.16 is no longer supported. + x := (*[1 << 30]big.Word)(unsafe.Pointer(&b[0]))[:len(b)] + return new(big.Int).SetBits(x) +} + +func GenerateKeyECDSA(curve string) (X, Y, D *big.Int, err error) { + x, y, d, err := openssl.GenerateKeyECDSA(curve) + if err != nil { + return nil, nil, nil, err + } + return Dec(x), Dec(y), Dec(d), nil +} + +type ecdsaSignature struct { + R, S *big.Int +} + +func SignECDSA(priv *openssl.PrivateKeyECDSA, hash []byte) (r, s *big.Int, err error) { + sig, err := openssl.SignMarshalECDSA(priv, hash) + if err != nil { + return nil, nil, err + } + var esig ecdsaSignature + if _, err := asn1.Unmarshal(sig, &esig); err != nil { + return nil, nil, err + } + return esig.R, esig.S, nil +} + +func NewPrivateKeyECDSA(curve string, X, Y, D *big.Int) (*openssl.PrivateKeyECDSA, error) { + return openssl.NewPrivateKeyECDSA(curve, Enc(X), Enc(Y), Enc(D)) +} + +func NewPublicKeyECDSA(curve string, X, Y *big.Int) (*openssl.PublicKeyECDSA, error) { + return openssl.NewPublicKeyECDSA(curve, Enc(X), Enc(Y)) +} + +func VerifyECDSA(pub *openssl.PublicKeyECDSA, hash []byte, r, s *big.Int) bool { + // We could use ECDSA_do_verify instead but would need to convert + // r and s to BIGNUM form. If we're going to do a conversion, marshaling + // to ASN.1 is more convenient and likely not much more expensive. + sig, err := asn1.Marshal(ecdsaSignature{r, s}) + if err != nil { + return false + } + return openssl.VerifyECDSA(pub, hash, sig) +} + +func GenerateKeyRSA(bits int) (N, E, D, P, Q, Dp, Dq, Qinv *big.Int, err error) { + bN, bE, bD, bP, bQ, bDp, bDq, bQinv, err1 := openssl.GenerateKeyRSA(bits) + if err1 != nil { + err = err1 + return + } + N = Dec(bN) + E = Dec(bE) + D = Dec(bD) + P = Dec(bP) + Q = Dec(bQ) + Dp = Dec(bDp) + Dq = Dec(bDq) + Qinv = Dec(bQinv) + return +} + +func NewPublicKeyRSA(N, E *big.Int) (*openssl.PublicKeyRSA, error) { + return openssl.NewPublicKeyRSA(Enc(N), Enc(E)) +} + +func NewPrivateKeyRSA(N, E, D, P, Q, Dp, Dq, Qinv *big.Int) (*openssl.PrivateKeyRSA, error) { + return openssl.NewPrivateKeyRSA(Enc(N), Enc(E), Enc(D), Enc(P), Enc(Q), Enc(Dp), Enc(Dq), Enc(Qinv)) +} diff --git a/openssl/ecdsa.go b/openssl/ecdsa.go index 84f82e9..e5a3e03 100644 --- a/openssl/ecdsa.go +++ b/openssl/ecdsa.go @@ -9,17 +9,11 @@ package openssl // #include "goopenssl.h" import "C" import ( - "encoding/asn1" "errors" - "math/big" "runtime" "unsafe" ) -type ecdsaSignature struct { - R, S *big.Int -} - type PrivateKeyECDSA struct { // _pkey MUST NOT be accessed directly. Instead, use the withKey method. _pkey C.GO_EVP_PKEY_PTR @@ -65,7 +59,7 @@ func curveNID(curve string) (C.int, error) { return 0, errUnknownCurve } -func NewPublicKeyECDSA(curve string, X, Y *big.Int) (*PublicKeyECDSA, error) { +func NewPublicKeyECDSA(curve string, X, Y BigInt) (*PublicKeyECDSA, error) { pkey, err := newECKey(curve, X, Y, nil) if err != nil { return nil, err @@ -79,7 +73,7 @@ func NewPublicKeyECDSA(curve string, X, Y *big.Int) (*PublicKeyECDSA, error) { return k, nil } -func newECKey(curve string, X, Y, D *big.Int) (pkey C.GO_EVP_PKEY_PTR, err error) { +func newECKey(curve string, X, Y, D BigInt) (pkey C.GO_EVP_PKEY_PTR, err error) { var nid C.int if nid, err = curveNID(curve); err != nil { return nil, err @@ -135,7 +129,7 @@ func newECKey(curve string, X, Y, D *big.Int) (pkey C.GO_EVP_PKEY_PTR, err error return pkey, nil } -func NewPrivateKeyECDSA(curve string, X, Y *big.Int, D *big.Int) (*PrivateKeyECDSA, error) { +func NewPrivateKeyECDSA(curve string, X, Y, D BigInt) (*PrivateKeyECDSA, error) { pkey, err := newECKey(curve, X, Y, D) if err != nil { return nil, err @@ -149,38 +143,15 @@ func NewPrivateKeyECDSA(curve string, X, Y *big.Int, D *big.Int) (*PrivateKeyECD return k, nil } -func SignECDSA(priv *PrivateKeyECDSA, hash []byte) (r, s *big.Int, err error) { - // We could use ECDSA_do_sign instead but would need to convert - // the resulting BIGNUMs to *big.Int form. If we're going to do a - // conversion, converting the ASN.1 form is more convenient and - // likely not much more expensive. - sig, err := SignMarshalECDSA(priv, hash) - if err != nil { - return nil, nil, err - } - var esig ecdsaSignature - if _, err := asn1.Unmarshal(sig, &esig); err != nil { - return nil, nil, err - } - return esig.R, esig.S, nil -} - func SignMarshalECDSA(priv *PrivateKeyECDSA, hash []byte) ([]byte, error) { return evpSign(priv.withKey, 0, 0, 0, hash) } -func VerifyECDSA(pub *PublicKeyECDSA, hash []byte, r, s *big.Int) bool { - // We could use ECDSA_do_verify instead but would need to convert - // r and s to BIGNUM form. If we're going to do a conversion, marshaling - // to ASN.1 is more convenient and likely not much more expensive. - sig, err := asn1.Marshal(ecdsaSignature{r, s}) - if err != nil { - return false - } +func VerifyECDSA(pub *PublicKeyECDSA, hash []byte, sig []byte) bool { return evpVerify(pub.withKey, 0, 0, 0, sig, hash) == nil } -func GenerateKeyECDSA(curve string) (X, Y, D *big.Int, err error) { +func GenerateKeyECDSA(curve string) (X, Y, D BigInt, err error) { pkey, err := generateEVPPKey(C.GO_EVP_PKEY_EC, 0, curve) if err != nil { return nil, nil, nil, err diff --git a/openssl/ecdsa_test.go b/openssl/ecdsa_test.go index 132a488..5207802 100644 --- a/openssl/ecdsa_test.go +++ b/openssl/ecdsa_test.go @@ -4,12 +4,14 @@ //go:build linux && !android // +build linux,!android -package openssl +package openssl_test import ( "crypto/ecdsa" "crypto/elliptic" "testing" + + "github.com/microsoft/go-crypto-openssl/openssl/bbig" ) func testAllCurves(t *testing.T, f func(*testing.T, elliptic.Curve)) { @@ -55,32 +57,32 @@ func testECDSASignAndVerify(t *testing.T, c elliptic.Curve) { t.Fatal(err) } - priv, err := NewPrivateKeyECDSA(key.Params().Name, key.X, key.Y, key.D) + priv, err := bbig.NewPrivateKeyECDSA(key.Params().Name, key.X, key.Y, key.D) if err != nil { t.Fatal(err) } hashed := []byte("testing") - r, s, err := SignECDSA(priv, hashed) + r, s, err := bbig.SignECDSA(priv, hashed) if err != nil { t.Errorf("error signing: %s", err) return } - pub, err := NewPublicKeyECDSA(key.Params().Name, key.X, key.Y) + pub, err := bbig.NewPublicKeyECDSA(key.Params().Name, key.X, key.Y) if err != nil { t.Fatal(err) } - if !VerifyECDSA(pub, hashed, r, s) { + if !bbig.VerifyECDSA(pub, hashed, r, s) { t.Errorf("Verify failed") } hashed[0] ^= 0xff - if VerifyECDSA(pub, hashed, r, s) { + if bbig.VerifyECDSA(pub, hashed, r, s) { t.Errorf("Verify succeeded despite intentionally invalid hash!") } } func generateKeycurve(c elliptic.Curve) (*ecdsa.PrivateKey, error) { - x, y, d, err := GenerateKeyECDSA(c.Params().Name) + x, y, d, err := bbig.GenerateKeyECDSA(c.Params().Name) if err != nil { return nil, err } diff --git a/openssl/openssl.go b/openssl/openssl.go index dfb6c0b..7c336ae 100644 --- a/openssl/openssl.go +++ b/openssl/openssl.go @@ -13,7 +13,6 @@ package openssl import "C" import ( "errors" - "math/big" "math/bits" "strconv" "strings" @@ -22,6 +21,11 @@ import ( "unsafe" ) +// A BigInt is the raw words from a BigInt. +// This definition allows us to avoid importing math/big. +// Conversion between BigInt and *big.Int is in openssl/bbig. +type BigInt []uint + var ( providerNameFips = C.CString("fips") providerNameDefault = C.CString("default") @@ -245,30 +249,29 @@ func (e fail) Error() string { return "openssl: " + string(e) + " failed" } const wordBytes = bits.UintSize / 8 -func wbase(b []big.Word) *C.uchar { +func wbase(b BigInt) *C.uchar { if len(b) == 0 { return nil } return (*C.uchar)(unsafe.Pointer(&b[0])) } -func bigToBN(x *big.Int) C.GO_BIGNUM_PTR { - if x == nil { +func bigToBN(x BigInt) C.GO_BIGNUM_PTR { + if len(x) == 0 { return nil } - raw := x.Bits() - return C.go_openssl_BN_lebin2bn(wbase(raw), C.int(len(raw)*wordBytes), nil) + return C.go_openssl_BN_lebin2bn(wbase(x), C.int(len(x)*wordBytes), nil) } -func bnToBig(bn C.GO_BIGNUM_PTR) *big.Int { +func bnToBig(bn C.GO_BIGNUM_PTR) BigInt { if bn == nil { return nil } - raw := make([]big.Word, C.go_openssl_BN_num_bits(bn)) - if C.go_openssl_BN_bn2lebinpad(bn, wbase(raw), C.int(len(raw)*wordBytes)) == 0 { + x := make(BigInt, C.go_openssl_BN_num_bits(bn)) + if C.go_openssl_BN_bn2lebinpad(bn, wbase(x), C.int(len(x)*wordBytes)) == 0 { panic("openssl: bignum conversion failed") } - return new(big.Int).SetBits(raw) + return x } // noescape hides a pointer from escape analysis. noescape is diff --git a/openssl/rsa.go b/openssl/rsa.go index 05ff62c..3d4aa14 100644 --- a/openssl/rsa.go +++ b/openssl/rsa.go @@ -13,13 +13,12 @@ import ( "crypto/subtle" "errors" "hash" - "math/big" "runtime" "unsafe" ) -func GenerateKeyRSA(bits int) (N, E, D, P, Q, Dp, Dq, Qinv *big.Int, err error) { - bad := func(e error) (N, E, D, P, Q, Dp, Dq, Qinv *big.Int, err error) { +func GenerateKeyRSA(bits int) (N, E, D, P, Q, Dp, Dq, Qinv BigInt, err error) { + bad := func(e error) (N, E, D, P, Q, Dp, Dq, Qinv BigInt, err error) { return nil, nil, nil, nil, nil, nil, nil, nil, e } pkey, err := generateEVPPKey(C.GO_EVP_PKEY_RSA, bits, "") @@ -42,7 +41,7 @@ type PublicKeyRSA struct { _pkey C.GO_EVP_PKEY_PTR } -func NewPublicKeyRSA(N, E *big.Int) (*PublicKeyRSA, error) { +func NewPublicKeyRSA(N, E BigInt) (*PublicKeyRSA, error) { key := C.go_openssl_RSA_new() if key == nil { return nil, newOpenSSLError("RSA_new failed") @@ -82,7 +81,7 @@ type PrivateKeyRSA struct { _pkey C.GO_EVP_PKEY_PTR } -func NewPrivateKeyRSA(N, E, D, P, Q, Dp, Dq, Qinv *big.Int) (*PrivateKeyRSA, error) { +func NewPrivateKeyRSA(N, E, D, P, Q, Dp, Dq, Qinv BigInt) (*PrivateKeyRSA, error) { key := C.go_openssl_RSA_new() if key == nil { return nil, newOpenSSLError("RSA_new failed") @@ -213,7 +212,7 @@ type rsa_st_1_0_2 struct { // It contains more fields, but we are not interesed on them. } -func bnSet(b1 *C.GO_BIGNUM_PTR, b2 *big.Int) { +func bnSet(b1 *C.GO_BIGNUM_PTR, b2 BigInt) { if b2 == nil { return } @@ -223,7 +222,7 @@ func bnSet(b1 *C.GO_BIGNUM_PTR, b2 *big.Int) { *b1 = bigToBN(b2) } -func rsaSetKey(key C.GO_RSA_PTR, n, e, d *big.Int) bool { +func rsaSetKey(key C.GO_RSA_PTR, n, e, d BigInt) bool { if vMajor == 1 && vMinor == 0 { r := (*rsa_st_1_0_2)(unsafe.Pointer(key)) //r.d and d will be nil for public keys. @@ -239,7 +238,7 @@ func rsaSetKey(key C.GO_RSA_PTR, n, e, d *big.Int) bool { return C.go_openssl_RSA_set0_key(key, bigToBN(n), bigToBN(e), bigToBN(d)) == 1 } -func rsaSetFactors(key C.GO_RSA_PTR, p, q *big.Int) bool { +func rsaSetFactors(key C.GO_RSA_PTR, p, q BigInt) bool { if vMajor == 1 && vMinor == 0 { r := (*rsa_st_1_0_2)(unsafe.Pointer(key)) if (r.p == nil && p == nil) || @@ -253,7 +252,7 @@ func rsaSetFactors(key C.GO_RSA_PTR, p, q *big.Int) bool { return C.go_openssl_RSA_set0_factors(key, bigToBN(p), bigToBN(q)) == 1 } -func rsaSetCRTParams(key C.GO_RSA_PTR, dmp1, dmq1, iqmp *big.Int) bool { +func rsaSetCRTParams(key C.GO_RSA_PTR, dmp1, dmq1, iqmp BigInt) bool { if vMajor == 1 && vMinor == 0 { r := (*rsa_st_1_0_2)(unsafe.Pointer(key)) if (r.dmp1 == nil && dmp1 == nil) || @@ -269,7 +268,7 @@ func rsaSetCRTParams(key C.GO_RSA_PTR, dmp1, dmq1, iqmp *big.Int) bool { return C.go_openssl_RSA_set0_crt_params(key, bigToBN(dmp1), bigToBN(dmq1), bigToBN(iqmp)) == 1 } -func rsaGetKey(key C.GO_RSA_PTR) (*big.Int, *big.Int, *big.Int) { +func rsaGetKey(key C.GO_RSA_PTR) (BigInt, BigInt, BigInt) { var n, e, d C.GO_BIGNUM_PTR if vMajor == 1 && vMinor == 0 { r := (*rsa_st_1_0_2)(unsafe.Pointer(key)) @@ -280,7 +279,7 @@ func rsaGetKey(key C.GO_RSA_PTR) (*big.Int, *big.Int, *big.Int) { return bnToBig(n), bnToBig(e), bnToBig(d) } -func rsaGetFactors(key C.GO_RSA_PTR) (*big.Int, *big.Int) { +func rsaGetFactors(key C.GO_RSA_PTR) (BigInt, BigInt) { var p, q C.GO_BIGNUM_PTR if vMajor == 1 && vMinor == 0 { r := (*rsa_st_1_0_2)(unsafe.Pointer(key)) @@ -291,7 +290,7 @@ func rsaGetFactors(key C.GO_RSA_PTR) (*big.Int, *big.Int) { return bnToBig(p), bnToBig(q) } -func rsaGetCRTParams(key C.GO_RSA_PTR) (*big.Int, *big.Int, *big.Int) { +func rsaGetCRTParams(key C.GO_RSA_PTR) (BigInt, BigInt, BigInt) { var dmp1, dmq1, iqmp C.GO_BIGNUM_PTR if vMajor == 1 && vMinor == 0 { r := (*rsa_st_1_0_2)(unsafe.Pointer(key)) diff --git a/openssl/rsa_test.go b/openssl/rsa_test.go index cccb6a1..32dc338 100644 --- a/openssl/rsa_test.go +++ b/openssl/rsa_test.go @@ -4,7 +4,7 @@ //go:build linux && !android // +build linux,!android -package openssl +package openssl_test import ( "bytes" @@ -12,6 +12,9 @@ import ( "math/big" "strconv" "testing" + + "github.com/microsoft/go-crypto-openssl/openssl" + "github.com/microsoft/go-crypto-openssl/openssl/bbig" ) func TestRSAKeyGeneration(t *testing.T) { @@ -20,11 +23,11 @@ func TestRSAKeyGeneration(t *testing.T) { t.Parallel() priv, pub := newRSAKey(t, size) msg := []byte("hi!") - enc, err := EncryptRSAPKCS1(pub, msg) + enc, err := openssl.EncryptRSAPKCS1(pub, msg) if err != nil { t.Fatalf("EncryptPKCS1v15: %v", err) } - dec, err := DecryptRSAPKCS1(priv, enc) + dec, err := openssl.DecryptRSAPKCS1(priv, enc) if err != nil { t.Fatalf("DecryptPKCS1v15: %v", err) } @@ -36,15 +39,15 @@ func TestRSAKeyGeneration(t *testing.T) { } func TestEncryptDecryptOAEP(t *testing.T) { - sha256 := NewSHA256() + sha256 := openssl.NewSHA256() msg := []byte("hi!") label := []byte("ho!") priv, pub := newRSAKey(t, 2048) - enc, err := EncryptRSAOAEP(sha256, pub, msg, label) + enc, err := openssl.EncryptRSAOAEP(sha256, pub, msg, label) if err != nil { t.Fatal(err) } - dec, err := DecryptRSAOAEP(sha256, priv, enc, label) + dec, err := openssl.DecryptRSAOAEP(sha256, priv, enc, label) if err != nil { t.Fatal(err) } @@ -54,14 +57,14 @@ func TestEncryptDecryptOAEP(t *testing.T) { } func TestEncryptDecryptOAEP_WrongLabel(t *testing.T) { - sha256 := NewSHA256() + sha256 := openssl.NewSHA256() msg := []byte("hi!") priv, pub := newRSAKey(t, 2048) - enc, err := EncryptRSAOAEP(sha256, pub, msg, []byte("ho!")) + enc, err := openssl.EncryptRSAOAEP(sha256, pub, msg, []byte("ho!")) if err != nil { t.Fatal(err) } - dec, err := DecryptRSAOAEP(sha256, priv, enc, []byte("wrong!")) + dec, err := openssl.DecryptRSAOAEP(sha256, priv, enc, []byte("wrong!")) if err == nil { t.Errorf("error expected") } @@ -71,15 +74,15 @@ func TestEncryptDecryptOAEP_WrongLabel(t *testing.T) { } func TestSignVerifyPKCS1v15(t *testing.T) { - sha256 := NewSHA256() + sha256 := openssl.NewSHA256() priv, pub := newRSAKey(t, 2048) sha256.Write([]byte("hi!")) hashed := sha256.Sum(nil) - signed, err := SignRSAPKCS1v15(priv, crypto.SHA256, hashed) + signed, err := openssl.SignRSAPKCS1v15(priv, crypto.SHA256, hashed) if err != nil { t.Fatal(err) } - err = VerifyRSAPKCS1v15(pub, crypto.SHA256, hashed, signed) + err = openssl.VerifyRSAPKCS1v15(pub, crypto.SHA256, hashed, signed) if err != nil { t.Fatal(err) } @@ -88,58 +91,58 @@ func TestSignVerifyPKCS1v15(t *testing.T) { func TestSignVerifyPKCS1v15_Unhashed(t *testing.T) { msg := []byte("hi!") priv, pub := newRSAKey(t, 2048) - signed, err := SignRSAPKCS1v15(priv, 0, msg) + signed, err := openssl.SignRSAPKCS1v15(priv, 0, msg) if err != nil { t.Fatal(err) } - err = VerifyRSAPKCS1v15(pub, 0, msg, signed) + err = openssl.VerifyRSAPKCS1v15(pub, 0, msg, signed) if err != nil { t.Fatal(err) } } func TestSignVerifyPKCS1v15_Invalid(t *testing.T) { - sha256 := NewSHA256() + sha256 := openssl.NewSHA256() msg := []byte("hi!") priv, pub := newRSAKey(t, 2048) sha256.Write(msg) hashed := sha256.Sum(nil) - signed, err := SignRSAPKCS1v15(priv, crypto.SHA256, hashed) + signed, err := openssl.SignRSAPKCS1v15(priv, crypto.SHA256, hashed) if err != nil { t.Fatal(err) } - err = VerifyRSAPKCS1v15(pub, crypto.SHA256, msg, signed) + err = openssl.VerifyRSAPKCS1v15(pub, crypto.SHA256, msg, signed) if err == nil { t.Fatal("error expected") } } func TestSignVerifyRSAPSS(t *testing.T) { - sha256 := NewSHA256() + sha256 := openssl.NewSHA256() priv, pub := newRSAKey(t, 2048) sha256.Write([]byte("testing")) hashed := sha256.Sum(nil) - signed, err := SignRSAPSS(priv, crypto.SHA256, hashed, 0) + signed, err := openssl.SignRSAPSS(priv, crypto.SHA256, hashed, 0) if err != nil { t.Fatal(err) } - err = VerifyRSAPSS(pub, crypto.SHA256, hashed, signed, 0) + err = openssl.VerifyRSAPSS(pub, crypto.SHA256, hashed, signed, 0) if err != nil { t.Fatal(err) } } -func newRSAKey(t *testing.T, size int) (*PrivateKeyRSA, *PublicKeyRSA) { +func newRSAKey(t *testing.T, size int) (*openssl.PrivateKeyRSA, *openssl.PublicKeyRSA) { t.Helper() - N, E, D, P, Q, Dp, Dq, Qinv, err := GenerateKeyRSA(size) + N, E, D, P, Q, Dp, Dq, Qinv, err := bbig.GenerateKeyRSA(size) if err != nil { t.Fatalf("GenerateKeyRSA(%d): %v", size, err) } - priv, err := NewPrivateKeyRSA(N, E, D, P, Q, Dp, Dq, Qinv) + priv, err := bbig.NewPrivateKeyRSA(N, E, D, P, Q, Dp, Dq, Qinv) if err != nil { t.Fatalf("NewPrivateKeyRSA(%d): %v", size, err) } - pub, err := NewPublicKeyRSA(N, E) + pub, err := bbig.NewPublicKeyRSA(N, E) if err != nil { t.Fatalf("NewPublicKeyRSA(%d): %v", size, err) } @@ -158,14 +161,24 @@ func BenchmarkEncryptRSAPKCS1(b *testing.B) { b.StopTimer() // Public key length should be at least of 2048 bits, else OpenSSL will report an error when running in FIPS mode. n := fromBase36("14314132931241006650998084889274020608918049032671858325988396851334124245188214251956198731333464217832226406088020736932173064754214329009979944037640912127943488972644697423190955557435910767690712778463524983667852819010259499695177313115447116110358524558307947613422897787329221478860907963827160223559690523660574329011927531289655711860504630573766609239332569210831325633840174683944553667352219670930408593321661375473885147973879086994006440025257225431977751512374815915392249179976902953721486040787792801849818254465486633791826766873076617116727073077821584676715609985777563958286637185868165868520557") - test2048PubKey, err := NewPublicKeyRSA(n, big.NewInt(3)) + test2048PubKey, err := bbig.NewPublicKeyRSA(n, big.NewInt(3)) if err != nil { b.Fatal(err) } b.StartTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { - if _, err := EncryptRSAPKCS1(test2048PubKey, []byte("testing")); err != nil { + if _, err := openssl.EncryptRSAPKCS1(test2048PubKey, []byte("testing")); err != nil { + b.Fatal(err) + } + } +} + +func BenchmarkGenerateKeyRSA(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + _, _, _, _, _, _, _, _, err := bbig.GenerateKeyRSA(2048) + if err != nil { b.Fatal(err) } } From 23872e5b90a23c748425469ace197486ad522f18 Mon Sep 17 00:00:00 2001 From: Quim Muntal Date: Tue, 17 May 2022 19:58:22 +0000 Subject: [PATCH 2/4] fix Enc and Dec --- openssl/bbig/big.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openssl/bbig/big.go b/openssl/bbig/big.go index d3bed4e..30dced0 100644 --- a/openssl/bbig/big.go +++ b/openssl/bbig/big.go @@ -26,7 +26,7 @@ func Enc(b *big.Int) openssl.BigInt { return openssl.BigInt{} } // TODO: Use unsafe.Slice((*uint)(&x[0]), len(x)) once go1.16 is no longer supported. - return (*[1 << 30]uint)(unsafe.Pointer(&x[0]))[:len(x)] + return (*(*[]uint)(unsafe.Pointer(&x)))[:len(x)] } func Dec(b openssl.BigInt) *big.Int { @@ -37,7 +37,7 @@ func Dec(b openssl.BigInt) *big.Int { return new(big.Int) } // TODO: Use unsafe.Slice((*uint)(&b[0]), len(b)) once go1.16 is no longer supported. - x := (*[1 << 30]big.Word)(unsafe.Pointer(&b[0]))[:len(b)] + x := (*(*[]big.Word)(unsafe.Pointer(&b)))[:len(b)] return new(big.Int).SetBits(x) } From 558632bb3963a959c11cc03d715b20bbc9b1354d Mon Sep 17 00:00:00 2001 From: Quim Muntal Date: Wed, 18 May 2022 14:44:20 +0000 Subject: [PATCH 3/4] move pre-go1.19 wrappers to bbig/bridge --- openssl/bbig/big.go | 72 ------------------------------ openssl/bbig/bridge/bridge.go | 83 +++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+), 72 deletions(-) create mode 100644 openssl/bbig/bridge/bridge.go diff --git a/openssl/bbig/big.go b/openssl/bbig/big.go index 30dced0..1214e10 100644 --- a/openssl/bbig/big.go +++ b/openssl/bbig/big.go @@ -1,6 +1,3 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - // Copyright 2022 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. @@ -10,7 +7,6 @@ package bbig import ( - "encoding/asn1" "math/big" "unsafe" @@ -40,71 +36,3 @@ func Dec(b openssl.BigInt) *big.Int { x := (*(*[]big.Word)(unsafe.Pointer(&b)))[:len(b)] return new(big.Int).SetBits(x) } - -func GenerateKeyECDSA(curve string) (X, Y, D *big.Int, err error) { - x, y, d, err := openssl.GenerateKeyECDSA(curve) - if err != nil { - return nil, nil, nil, err - } - return Dec(x), Dec(y), Dec(d), nil -} - -type ecdsaSignature struct { - R, S *big.Int -} - -func SignECDSA(priv *openssl.PrivateKeyECDSA, hash []byte) (r, s *big.Int, err error) { - sig, err := openssl.SignMarshalECDSA(priv, hash) - if err != nil { - return nil, nil, err - } - var esig ecdsaSignature - if _, err := asn1.Unmarshal(sig, &esig); err != nil { - return nil, nil, err - } - return esig.R, esig.S, nil -} - -func NewPrivateKeyECDSA(curve string, X, Y, D *big.Int) (*openssl.PrivateKeyECDSA, error) { - return openssl.NewPrivateKeyECDSA(curve, Enc(X), Enc(Y), Enc(D)) -} - -func NewPublicKeyECDSA(curve string, X, Y *big.Int) (*openssl.PublicKeyECDSA, error) { - return openssl.NewPublicKeyECDSA(curve, Enc(X), Enc(Y)) -} - -func VerifyECDSA(pub *openssl.PublicKeyECDSA, hash []byte, r, s *big.Int) bool { - // We could use ECDSA_do_verify instead but would need to convert - // r and s to BIGNUM form. If we're going to do a conversion, marshaling - // to ASN.1 is more convenient and likely not much more expensive. - sig, err := asn1.Marshal(ecdsaSignature{r, s}) - if err != nil { - return false - } - return openssl.VerifyECDSA(pub, hash, sig) -} - -func GenerateKeyRSA(bits int) (N, E, D, P, Q, Dp, Dq, Qinv *big.Int, err error) { - bN, bE, bD, bP, bQ, bDp, bDq, bQinv, err1 := openssl.GenerateKeyRSA(bits) - if err1 != nil { - err = err1 - return - } - N = Dec(bN) - E = Dec(bE) - D = Dec(bD) - P = Dec(bP) - Q = Dec(bQ) - Dp = Dec(bDp) - Dq = Dec(bDq) - Qinv = Dec(bQinv) - return -} - -func NewPublicKeyRSA(N, E *big.Int) (*openssl.PublicKeyRSA, error) { - return openssl.NewPublicKeyRSA(Enc(N), Enc(E)) -} - -func NewPrivateKeyRSA(N, E, D, P, Q, Dp, Dq, Qinv *big.Int) (*openssl.PrivateKeyRSA, error) { - return openssl.NewPrivateKeyRSA(Enc(N), Enc(E), Enc(D), Enc(P), Enc(Q), Enc(Dp), Enc(Dq), Enc(Qinv)) -} diff --git a/openssl/bbig/bridge/bridge.go b/openssl/bbig/bridge/bridge.go new file mode 100644 index 0000000..17279f1 --- /dev/null +++ b/openssl/bbig/bridge/bridge.go @@ -0,0 +1,83 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +// These wrappers only exist for code reuse in places where we need the old pre-go1.19 signature. + +package bbig + +import ( + "encoding/asn1" + "math/big" + + "github.com/microsoft/go-crypto-openssl/openssl" + "github.com/microsoft/go-crypto-openssl/openssl/bbig" +) + +func GenerateKeyECDSA(curve string) (X, Y, D *big.Int, err error) { + x, y, d, err := openssl.GenerateKeyECDSA(curve) + if err != nil { + return nil, nil, nil, err + } + return bbig.Dec(x), bbig.Dec(y), bbig.Dec(d), nil +} + +type ecdsaSignature struct { + R, S *big.Int +} + +func SignECDSA(priv *openssl.PrivateKeyECDSA, hash []byte) (r, s *big.Int, err error) { + sig, err := openssl.SignMarshalECDSA(priv, hash) + if err != nil { + return nil, nil, err + } + var esig ecdsaSignature + if _, err := asn1.Unmarshal(sig, &esig); err != nil { + return nil, nil, err + } + return esig.R, esig.S, nil +} + +func NewPrivateKeyECDSA(curve string, X, Y, D *big.Int) (*openssl.PrivateKeyECDSA, error) { + return openssl.NewPrivateKeyECDSA(curve, bbig.Enc(X), bbig.Enc(Y), bbig.Enc(D)) +} + +func NewPublicKeyECDSA(curve string, X, Y *big.Int) (*openssl.PublicKeyECDSA, error) { + return openssl.NewPublicKeyECDSA(curve, bbig.Enc(X), bbig.Enc(Y)) +} + +func VerifyECDSA(pub *openssl.PublicKeyECDSA, hash []byte, r, s *big.Int) bool { + sig, err := asn1.Marshal(ecdsaSignature{r, s}) + if err != nil { + return false + } + return openssl.VerifyECDSA(pub, hash, sig) +} + +func GenerateKeyRSA(bits int) (N, E, D, P, Q, Dp, Dq, Qinv *big.Int, err error) { + bN, bE, bD, bP, bQ, bDp, bDq, bQinv, err1 := openssl.GenerateKeyRSA(bits) + if err1 != nil { + err = err1 + return + } + N = bbig.Dec(bN) + E = bbig.Dec(bE) + D = bbig.Dec(bD) + P = bbig.Dec(bP) + Q = bbig.Dec(bQ) + Dp = bbig.Dec(bDp) + Dq = bbig.Dec(bDq) + Qinv = bbig.Dec(bQinv) + return +} + +func NewPublicKeyRSA(N, E *big.Int) (*openssl.PublicKeyRSA, error) { + return openssl.NewPublicKeyRSA(bbig.Enc(N), bbig.Enc(E)) +} + +func NewPrivateKeyRSA(N, E, D, P, Q, Dp, Dq, Qinv *big.Int) (*openssl.PrivateKeyRSA, error) { + return openssl.NewPrivateKeyRSA( + bbig.Enc(N), bbig.Enc(E), bbig.Enc(D), + bbig.Enc(P), bbig.Enc(Q), + bbig.Enc(Dp), bbig.Enc(Dq), bbig.Enc(Qinv), + ) +} From b69c23e4147fabe5ae337c97936be6836587d78d Mon Sep 17 00:00:00 2001 From: Quim Muntal Date: Wed, 18 May 2022 14:58:54 +0000 Subject: [PATCH 4/4] fix compilation --- openssl/bbig/bridge/bridge.go | 2 +- openssl/ecdsa_test.go | 14 +++++++------- openssl/rsa_test.go | 12 ++++++------ 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/openssl/bbig/bridge/bridge.go b/openssl/bbig/bridge/bridge.go index 17279f1..43f5e60 100644 --- a/openssl/bbig/bridge/bridge.go +++ b/openssl/bbig/bridge/bridge.go @@ -3,7 +3,7 @@ // These wrappers only exist for code reuse in places where we need the old pre-go1.19 signature. -package bbig +package bridge import ( "encoding/asn1" diff --git a/openssl/ecdsa_test.go b/openssl/ecdsa_test.go index 5207802..7219bde 100644 --- a/openssl/ecdsa_test.go +++ b/openssl/ecdsa_test.go @@ -11,7 +11,7 @@ import ( "crypto/elliptic" "testing" - "github.com/microsoft/go-crypto-openssl/openssl/bbig" + "github.com/microsoft/go-crypto-openssl/openssl/bbig/bridge" ) func testAllCurves(t *testing.T, f func(*testing.T, elliptic.Curve)) { @@ -57,32 +57,32 @@ func testECDSASignAndVerify(t *testing.T, c elliptic.Curve) { t.Fatal(err) } - priv, err := bbig.NewPrivateKeyECDSA(key.Params().Name, key.X, key.Y, key.D) + priv, err := bridge.NewPrivateKeyECDSA(key.Params().Name, key.X, key.Y, key.D) if err != nil { t.Fatal(err) } hashed := []byte("testing") - r, s, err := bbig.SignECDSA(priv, hashed) + r, s, err := bridge.SignECDSA(priv, hashed) if err != nil { t.Errorf("error signing: %s", err) return } - pub, err := bbig.NewPublicKeyECDSA(key.Params().Name, key.X, key.Y) + pub, err := bridge.NewPublicKeyECDSA(key.Params().Name, key.X, key.Y) if err != nil { t.Fatal(err) } - if !bbig.VerifyECDSA(pub, hashed, r, s) { + if !bridge.VerifyECDSA(pub, hashed, r, s) { t.Errorf("Verify failed") } hashed[0] ^= 0xff - if bbig.VerifyECDSA(pub, hashed, r, s) { + if bridge.VerifyECDSA(pub, hashed, r, s) { t.Errorf("Verify succeeded despite intentionally invalid hash!") } } func generateKeycurve(c elliptic.Curve) (*ecdsa.PrivateKey, error) { - x, y, d, err := bbig.GenerateKeyECDSA(c.Params().Name) + x, y, d, err := bridge.GenerateKeyECDSA(c.Params().Name) if err != nil { return nil, err } diff --git a/openssl/rsa_test.go b/openssl/rsa_test.go index 32dc338..e710cc4 100644 --- a/openssl/rsa_test.go +++ b/openssl/rsa_test.go @@ -14,7 +14,7 @@ import ( "testing" "github.com/microsoft/go-crypto-openssl/openssl" - "github.com/microsoft/go-crypto-openssl/openssl/bbig" + "github.com/microsoft/go-crypto-openssl/openssl/bbig/bridge" ) func TestRSAKeyGeneration(t *testing.T) { @@ -134,15 +134,15 @@ func TestSignVerifyRSAPSS(t *testing.T) { func newRSAKey(t *testing.T, size int) (*openssl.PrivateKeyRSA, *openssl.PublicKeyRSA) { t.Helper() - N, E, D, P, Q, Dp, Dq, Qinv, err := bbig.GenerateKeyRSA(size) + N, E, D, P, Q, Dp, Dq, Qinv, err := bridge.GenerateKeyRSA(size) if err != nil { t.Fatalf("GenerateKeyRSA(%d): %v", size, err) } - priv, err := bbig.NewPrivateKeyRSA(N, E, D, P, Q, Dp, Dq, Qinv) + priv, err := bridge.NewPrivateKeyRSA(N, E, D, P, Q, Dp, Dq, Qinv) if err != nil { t.Fatalf("NewPrivateKeyRSA(%d): %v", size, err) } - pub, err := bbig.NewPublicKeyRSA(N, E) + pub, err := bridge.NewPublicKeyRSA(N, E) if err != nil { t.Fatalf("NewPublicKeyRSA(%d): %v", size, err) } @@ -161,7 +161,7 @@ func BenchmarkEncryptRSAPKCS1(b *testing.B) { b.StopTimer() // Public key length should be at least of 2048 bits, else OpenSSL will report an error when running in FIPS mode. n := fromBase36("14314132931241006650998084889274020608918049032671858325988396851334124245188214251956198731333464217832226406088020736932173064754214329009979944037640912127943488972644697423190955557435910767690712778463524983667852819010259499695177313115447116110358524558307947613422897787329221478860907963827160223559690523660574329011927531289655711860504630573766609239332569210831325633840174683944553667352219670930408593321661375473885147973879086994006440025257225431977751512374815915392249179976902953721486040787792801849818254465486633791826766873076617116727073077821584676715609985777563958286637185868165868520557") - test2048PubKey, err := bbig.NewPublicKeyRSA(n, big.NewInt(3)) + test2048PubKey, err := bridge.NewPublicKeyRSA(n, big.NewInt(3)) if err != nil { b.Fatal(err) } @@ -177,7 +177,7 @@ func BenchmarkEncryptRSAPKCS1(b *testing.B) { func BenchmarkGenerateKeyRSA(b *testing.B) { b.ReportAllocs() for i := 0; i < b.N; i++ { - _, _, _, _, _, _, _, _, err := bbig.GenerateKeyRSA(2048) + _, _, _, _, _, _, _, _, err := bridge.GenerateKeyRSA(2048) if err != nil { b.Fatal(err) }