-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
469 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,278 @@ | ||
//go:build !cmd_go_bootstrap | ||
|
||
package openssl | ||
|
||
// #include "goopenssl.h" | ||
import "C" | ||
import ( | ||
"runtime" | ||
"unsafe" | ||
) | ||
|
||
var ( | ||
paramPbits = C.CString("pbits") | ||
paramQbits = C.CString("qbits") | ||
paramP = C.CString("p") | ||
paramQ = C.CString("q") | ||
paramG = C.CString("g") | ||
) | ||
|
||
// DSAParameters contains the DSA parameters. | ||
type DSAParameters struct { | ||
P, Q, G BigInt | ||
} | ||
|
||
func (p DSAParameters) keySize() uint32 { | ||
return uint32(len(p.P)) | ||
} | ||
|
||
func (p DSAParameters) groupSize() uint32 { | ||
return uint32(len(p.Q)) | ||
} | ||
|
||
// PrivateKeyDSA represents a DSA private key. | ||
type PrivateKeyDSA struct { | ||
DSAParameters | ||
X, Y BigInt | ||
|
||
_pkey C.GO_EVP_PKEY_PTR | ||
} | ||
|
||
func (k *PrivateKeyDSA) finalize() { | ||
C.go_openssl_EVP_PKEY_free(k._pkey) | ||
} | ||
|
||
func (k *PrivateKeyDSA) withKey(f func(C.GO_EVP_PKEY_PTR) C.int) C.int { | ||
defer runtime.KeepAlive(k) | ||
return f(k._pkey) | ||
} | ||
|
||
// PublicKeyDSA represents a DSA public key. | ||
type PublicKeyDSA struct { | ||
DSAParameters | ||
Y BigInt | ||
|
||
_pkey C.GO_EVP_PKEY_PTR | ||
} | ||
|
||
func (k *PublicKeyDSA) finalize() { | ||
C.go_openssl_EVP_PKEY_free(k._pkey) | ||
} | ||
|
||
func (k *PublicKeyDSA) withKey(f func(C.GO_EVP_PKEY_PTR) C.int) C.int { | ||
defer runtime.KeepAlive(k) | ||
return f(k._pkey) | ||
} | ||
|
||
// GenerateDSAParameters generates a set of DSA parameters. | ||
func GenerateDSAParameters(L, N int) (DSAParameters, error) { | ||
ctx := C.go_openssl_EVP_PKEY_CTX_new_id(C.GO_EVP_PKEY_DSA, nil) | ||
if ctx == nil { | ||
return DSAParameters{}, newOpenSSLError("EVP_PKEY_CTX_new_id failed") | ||
} | ||
defer C.go_openssl_EVP_PKEY_CTX_free(ctx) | ||
if C.go_openssl_EVP_PKEY_paramgen_init(ctx) != 1 { | ||
return DSAParameters{}, newOpenSSLError("EVP_PKEY_paramgen_init failed") | ||
} | ||
if C.go_openssl_EVP_PKEY_CTX_ctrl(ctx, C.GO_EVP_PKEY_DSA, -1, C.GO_EVP_PKEY_CTRL_DSA_PARAMGEN_BITS, C.int(L), nil) != 1 { | ||
return DSAParameters{}, newOpenSSLError("EVP_PKEY_CTX_ctrl failed") | ||
} | ||
if C.go_openssl_EVP_PKEY_CTX_ctrl(ctx, C.GO_EVP_PKEY_DSA, -1, C.GO_EVP_PKEY_CTRL_DSA_PARAMGEN_Q_BITS, C.int(N), nil) != 1 { | ||
return DSAParameters{}, newOpenSSLError("EVP_PKEY_CTX_ctrl failed") | ||
} | ||
var pkey C.GO_EVP_PKEY_PTR | ||
if C.go_openssl_EVP_PKEY_paramgen(ctx, &pkey) != 1 { | ||
return DSAParameters{}, newOpenSSLError("EVP_PKEY_paramgen failed") | ||
} | ||
defer C.go_openssl_EVP_PKEY_free(pkey) | ||
var p, q, g C.GO_BIGNUM_PTR | ||
switch vMajor { | ||
case 1: | ||
dsa := getDSA(pkey) | ||
C.go_openssl_DSA_get0_pqg(dsa, &p, &q, &g) | ||
case 3: | ||
defer func() { | ||
C.go_openssl_BN_free(p) | ||
C.go_openssl_BN_free(q) | ||
C.go_openssl_BN_free(g) | ||
}() | ||
if C.go_openssl_EVP_PKEY_get_bn_param(pkey, paramP, &p) != 1 || | ||
C.go_openssl_EVP_PKEY_get_bn_param(pkey, paramQ, &q) != 1 || | ||
C.go_openssl_EVP_PKEY_get_bn_param(pkey, paramG, &g) != 1 { | ||
return DSAParameters{}, newOpenSSLError("EVP_PKEY_get_bn_param") | ||
} | ||
default: | ||
panic(errUnsupportedVersion()) | ||
} | ||
|
||
return DSAParameters{ | ||
P: bnToBig(p), | ||
Q: bnToBig(q), | ||
G: bnToBig(g), | ||
}, nil | ||
} | ||
|
||
// NewPrivateKeyDSA creates a new DSA private key from the given parameters. | ||
func NewPrivateKeyDSA(params DSAParameters, X, Y BigInt) (*PrivateKeyDSA, error) { | ||
if X == nil || Y == nil { | ||
panic("X and Y must not be nil") | ||
} | ||
pkey, err := newDSA(params, X, Y) | ||
if err != nil { | ||
return nil, err | ||
} | ||
k := &PrivateKeyDSA{params, X, Y, pkey} | ||
runtime.SetFinalizer(k, (*PrivateKeyDSA).finalize) | ||
return k, nil | ||
} | ||
|
||
// NewPublicKeyDSA creates a new DSA public key from the given parameters. | ||
func NewPublicKeyDSA(params DSAParameters, Y BigInt) (*PublicKeyDSA, error) { | ||
if Y == nil { | ||
panic("Y must not be nil") | ||
} | ||
pkey, err := newDSA(params, nil, Y) | ||
if err != nil { | ||
return nil, err | ||
} | ||
k := &PublicKeyDSA{params, Y, pkey} | ||
runtime.SetFinalizer(k, (*PublicKeyDSA).finalize) | ||
return k, nil | ||
} | ||
|
||
// GenerateKeyDSA generates a new private DSA key using the given parameters. | ||
func GenerateKeyDSA(params DSAParameters) (*PrivateKeyDSA, error) { | ||
pkey, err := newDSA(params, nil, nil) | ||
if err != nil { | ||
return nil, err | ||
} | ||
var x, y C.GO_BIGNUM_PTR | ||
switch vMajor { | ||
case 1: | ||
dsa := getDSA(pkey) | ||
C.go_openssl_DSA_get0_key(dsa, &y, &x) | ||
case 3: | ||
defer func() { | ||
C.go_openssl_BN_free(x) | ||
C.go_openssl_BN_free(y) | ||
}() | ||
if C.go_openssl_EVP_PKEY_get_bn_param(pkey, paramPubKey, &y) != 1 || | ||
C.go_openssl_EVP_PKEY_get_bn_param(pkey, paramPrivKey, &x) != 1 { | ||
return nil, newOpenSSLError("EVP_PKEY_get_bn_param") | ||
} | ||
default: | ||
panic(errUnsupportedVersion()) | ||
} | ||
k := &PrivateKeyDSA{params, bnToBig(x), bnToBig(y), pkey} | ||
runtime.SetFinalizer(k, (*PrivateKeyDSA).finalize) | ||
return k, nil | ||
} | ||
|
||
// SignDSA signs a hash (which should be the result of hashing a larger message). | ||
func SignDSA(priv *PrivateKeyDSA, hash []byte) ([]byte, error) { | ||
return evpSign(priv.withKey, 0, 0, 0, hash) | ||
} | ||
|
||
// VerifyDSA verifiessig using the public key, pub. | ||
func VerifyDSA(pub *PublicKeyDSA, hash []byte, sig []byte) bool { | ||
return evpVerify(pub.withKey, 0, 0, 0, sig, hash) == nil | ||
} | ||
|
||
func newDSA(params DSAParameters, X, Y BigInt) (C.GO_EVP_PKEY_PTR, error) { | ||
switch vMajor { | ||
case 1: | ||
return newDSA1(params, X, Y) | ||
case 3: | ||
return newDSA3(params, X, Y) | ||
default: | ||
panic(errUnsupportedVersion()) | ||
} | ||
} | ||
|
||
func newDSA1(params DSAParameters, X, Y BigInt) (C.GO_EVP_PKEY_PTR, error) { | ||
if vMajor != 1 { | ||
panic("incorrect vMajor version") | ||
} | ||
dsa := C.go_openssl_DSA_new() | ||
p, q, g := bigToBN(params.P), bigToBN(params.Q), bigToBN(params.G) | ||
if C.go_openssl_DSA_set0_pqg(dsa, p, q, g) != 1 { | ||
C.go_openssl_DSA_free(dsa) | ||
return nil, newOpenSSLError("DSA_set0_pqg failed") | ||
} | ||
if Y != nil { | ||
pub, priv := bigToBN(Y), bigToBN(X) | ||
if C.go_openssl_DSA_set0_key(dsa, pub, priv) != 1 { | ||
C.go_openssl_DSA_free(dsa) | ||
return nil, newOpenSSLError("DSA_set0_key failed") | ||
} | ||
} else { | ||
if C.go_openssl_DSA_generate_key(dsa) != 1 { | ||
C.go_openssl_DSA_free(dsa) | ||
return nil, newOpenSSLError("DSA_generate_key failed") | ||
} | ||
} | ||
pkey := C.go_openssl_EVP_PKEY_new() | ||
if pkey == nil { | ||
C.go_openssl_DSA_free(dsa) | ||
return nil, newOpenSSLError("EVP_PKEY_new failed") | ||
} | ||
if C.go_openssl_EVP_PKEY_assign(pkey, C.GO_EVP_PKEY_DSA, unsafe.Pointer(dsa)) != 1 { | ||
C.go_openssl_DSA_free(dsa) | ||
C.go_openssl_EVP_PKEY_free(pkey) | ||
return nil, newOpenSSLError("EVP_PKEY_assign failed") | ||
} | ||
return pkey, nil | ||
} | ||
|
||
func newDSA3(params DSAParameters, X, Y BigInt) (C.GO_EVP_PKEY_PTR, error) { | ||
if vMajor != 3 { | ||
panic("incorrect vMajor version") | ||
} | ||
bld := C.go_openssl_OSSL_PARAM_BLD_new() | ||
if bld == nil { | ||
return nil, newOpenSSLError("OSSL_PARAM_BLD_new") | ||
} | ||
defer C.go_openssl_OSSL_PARAM_BLD_free(bld) | ||
pub, priv := bigToBN(Y), bigToBN(X) | ||
selection := C.int(C.GO_EVP_PKEY_PUBLIC_KEY) | ||
if C.go_openssl_OSSL_PARAM_BLD_push_BN(bld, paramPubKey, pub) != 1 { | ||
return nil, newOpenSSLError("OSSL_PARAM_BLD_push_BN") | ||
} | ||
if X != nil { | ||
if C.go_openssl_OSSL_PARAM_BLD_push_BN(bld, paramPrivKey, priv) != 1 { | ||
return nil, newOpenSSLError("OSSL_PARAM_BLD_push_BN") | ||
} | ||
selection = C.GO_EVP_PKEY_KEYPAIR | ||
} | ||
bldparams := C.go_openssl_OSSL_PARAM_BLD_to_param(bld) | ||
if bldparams == nil { | ||
return nil, newOpenSSLError("OSSL_PARAM_BLD_to_param") | ||
} | ||
defer C.go_openssl_OSSL_PARAM_free(bldparams) | ||
pkey, err := newEvpFromParams(C.GO_EVP_PKEY_EC, selection, bldparams) | ||
if err != nil { | ||
return nil, err | ||
} | ||
if Y != nil { | ||
return pkey, nil | ||
} | ||
// Generate the key. | ||
return nil, nil | ||
} | ||
|
||
// getDSA returns the DSA from pkey. | ||
// If pkey does not contain an DSA it panics. | ||
// The returned key should not be freed. | ||
func getDSA(pkey C.GO_EVP_PKEY_PTR) (key C.GO_DSA_PTR) { | ||
if vMajor == 1 && vMinor == 0 { | ||
if key0 := C.go_openssl_EVP_PKEY_get0(pkey); key0 != nil { | ||
key = C.GO_DSA_PTR(key0) | ||
} | ||
} else { | ||
key = C.go_openssl_EVP_PKEY_get0_DSA(pkey) | ||
} | ||
if key == nil { | ||
panic("pkey does not contain an DSA") | ||
} | ||
return key | ||
} |
Oops, something went wrong.