Skip to content

Commit

Permalink
Generate PKEYs using EVP_PKEY_Q_keygen (#229)
Browse files Browse the repository at this point in the history
* generate PKEYs using EVP_PKEY_Q_keygen

* Update shims.h

Co-authored-by: Davis Goodin <[email protected]>

* Update comment on variadic functions

* Fix indentation in generateEVPPKey function

* Refactor curveID handling in generateEVPPKey

---------

Co-authored-by: Davis Goodin <[email protected]>
  • Loading branch information
qmuntal and dagood authored Dec 10, 2024
1 parent bdc3592 commit dd4074a
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 24 deletions.
5 changes: 5 additions & 0 deletions cmd/checkheader/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,11 @@ func tryConvertDefineFunc(w io.Writer, l string, i int) bool {
if !strings.HasPrefix(l, "DEFINEFUNC") {
return false
}
if strings.HasPrefix(l, "DEFINEFUNC_VARIADIC") {
// Variadic functions are not supported. There is not enough
// information in the macro to create use it in writeDefineFunc.
return false
}
i1 := strings.IndexByte(l, '(')
// The first ")," match is always the end of the argument list parameter.
// We are not interested in the last parameter and parsing them would complicate the algorithm.
Expand Down
5 changes: 1 addition & 4 deletions ed25519.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"runtime"
"strconv"
"sync"
"unsafe"
)

const (
Expand Down Expand Up @@ -37,9 +36,7 @@ var supportsEd25519 = sync.OnceValue(func() bool {
}
}
case 3:
name := C.CString("ED25519")
defer C.free(unsafe.Pointer(name))
sig := C.go_openssl_EVP_SIGNATURE_fetch(nil, name, nil)
sig := C.go_openssl_EVP_SIGNATURE_fetch(nil, keyTypeED25519, nil)
if sig != nil {
C.go_openssl_EVP_SIGNATURE_free(sig)
return true
Expand Down
66 changes: 46 additions & 20 deletions evp.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ import (
"unsafe"
)

var (
keyTypeRSA = C.CString("RSA")
keyTypeEC = C.CString("EC")
keyTypeED25519 = C.CString("ED25519")
)

// cacheMD is a cache of crypto.Hash to GO_EVP_MD_PTR.
var cacheMD sync.Map

Expand Down Expand Up @@ -157,33 +163,53 @@ func cryptoHashToMD(ch crypto.Hash) (md C.GO_EVP_MD_PTR) {
return nil
}

// generateEVPPKey generates a new EVP_PKEY with the given id and properties.
func generateEVPPKey(id C.int, bits int, curve string) (C.GO_EVP_PKEY_PTR, error) {
if bits != 0 && curve != "" {
return nil, fail("incorrect generateEVPPKey parameters")
}
ctx := C.go_openssl_EVP_PKEY_CTX_new_id(id, nil)
if ctx == nil {
return nil, newOpenSSLError("EVP_PKEY_CTX_new_id failed")
}
defer C.go_openssl_EVP_PKEY_CTX_free(ctx)
if C.go_openssl_EVP_PKEY_keygen_init(ctx) != 1 {
return nil, newOpenSSLError("EVP_PKEY_keygen_init failed")
}
if bits != 0 {
if C.go_openssl_EVP_PKEY_CTX_ctrl(ctx, id, -1, C.GO_EVP_PKEY_CTRL_RSA_KEYGEN_BITS, C.int(bits), nil) != 1 {
return nil, newOpenSSLError("EVP_PKEY_CTX_ctrl failed")
var pkey C.GO_EVP_PKEY_PTR
switch vMajor {
case 1:
ctx := C.go_openssl_EVP_PKEY_CTX_new_id(id, nil)
if ctx == nil {
return nil, newOpenSSLError("EVP_PKEY_CTX_new_id")
}
defer C.go_openssl_EVP_PKEY_CTX_free(ctx)
if C.go_openssl_EVP_PKEY_keygen_init(ctx) != 1 {
return nil, newOpenSSLError("EVP_PKEY_keygen_init")
}
if bits != 0 {
if C.go_openssl_EVP_PKEY_CTX_ctrl(ctx, id, -1, C.GO_EVP_PKEY_CTRL_RSA_KEYGEN_BITS, C.int(bits), nil) != 1 {
return nil, newOpenSSLError("EVP_PKEY_CTX_ctrl")
}
}
}
if curve != "" {
nid := curveNID(curve)
if C.go_openssl_EVP_PKEY_CTX_ctrl(ctx, id, -1, C.GO_EVP_PKEY_CTRL_EC_PARAMGEN_CURVE_NID, nid, nil) != 1 {
return nil, newOpenSSLError("EVP_PKEY_CTX_ctrl failed")
if curve != "" {
if C.go_openssl_EVP_PKEY_CTX_ctrl(ctx, id, -1, C.GO_EVP_PKEY_CTRL_EC_PARAMGEN_CURVE_NID, curveNID(curve), nil) != 1 {
return nil, newOpenSSLError("EVP_PKEY_CTX_ctrl")
}
}
if C.go_openssl_EVP_PKEY_keygen(ctx, &pkey) != 1 {
return nil, newOpenSSLError("EVP_PKEY_keygen")
}
case 3:
switch id {
case C.GO_EVP_PKEY_RSA:
pkey = C.go_openssl_EVP_PKEY_Q_keygen_RSA(nil, nil, keyTypeRSA, C.size_t(bits))
case C.GO_EVP_PKEY_EC:
pkey = C.go_openssl_EVP_PKEY_Q_keygen_EC(nil, nil, keyTypeEC, C.go_openssl_OBJ_nid2sn(curveNID(curve)))
case C.GO_EVP_PKEY_ED25519:
pkey = C.go_openssl_EVP_PKEY_Q_keygen(nil, nil, keyTypeED25519)
default:
panic("unsupported key type '" + strconv.Itoa(int(id)) + "'")
}
if pkey == nil {
return nil, newOpenSSLError("EVP_PKEY_Q_keygen")
}
default:
panic(errUnsupportedVersion())
}
var pkey C.GO_EVP_PKEY_PTR
if C.go_openssl_EVP_PKEY_keygen(ctx, &pkey) != 1 {
return nil, newOpenSSLError("EVP_PKEY_keygen failed")
}

return pkey, nil
}

Expand Down
8 changes: 8 additions & 0 deletions goopenssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#define DEFINEFUNC_3_0(ret, func, args, argscall) DEFINEFUNC(ret, func, args, argscall)
#define DEFINEFUNC_RENAMED_1_1(ret, func, oldfunc, args, argscall) DEFINEFUNC(ret, func, args, argscall)
#define DEFINEFUNC_RENAMED_3_0(ret, func, oldfunc, args, argscall) DEFINEFUNC(ret, func, args, argscall)
#define DEFINEFUNC_VARIADIC_3_0(ret, func, newname, args, argscall) DEFINEFUNC(ret, newname, args, argscall)

FOR_ALL_OPENSSL_FUNCTIONS

Expand All @@ -34,6 +35,7 @@ FOR_ALL_OPENSSL_FUNCTIONS
#undef DEFINEFUNC_3_0
#undef DEFINEFUNC_RENAMED_1_1
#undef DEFINEFUNC_RENAMED_3_0
#undef DEFINEFUNC_VARIADIC_3_0

// go_openssl_fips_enabled returns 1 if FIPS mode is enabled, 0 otherwise.
// As a special case, it returns -1 if it cannot determine if FIPS mode is enabled.
Expand Down Expand Up @@ -140,6 +142,11 @@ go_openssl_load_functions(void* handle, unsigned int major, unsigned int minor,
{ \
DEFINEFUNC_INTERNAL(func, #func) \
}
#define DEFINEFUNC_VARIADIC_3_0(ret, func, newname, args, argscall) \
if (major == 3) \
{ \
DEFINEFUNC_INTERNAL(newname, #func) \
}

FOR_ALL_OPENSSL_FUNCTIONS

Expand All @@ -152,6 +159,7 @@ FOR_ALL_OPENSSL_FUNCTIONS
#undef DEFINEFUNC_3_0
#undef DEFINEFUNC_RENAMED_1_1
#undef DEFINEFUNC_RENAMED_3_0
#undef DEFINEFUNC_VARIADIC_3_0
}

static unsigned long
Expand Down
3 changes: 3 additions & 0 deletions goopenssl.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ int go_openssl_DSA_set0_key_backport(GO_DSA_PTR d, GO_BIGNUM_PTR pub_key, GO_BIG
DEFINEFUNC(ret, func, args, argscall)
#define DEFINEFUNC_RENAMED_3_0(ret, func, oldfunc, args, argscall) \
DEFINEFUNC(ret, func, args, argscall)
#define DEFINEFUNC_VARIADIC_3_0(ret, func, newname, args, argscall) \
DEFINEFUNC(ret, newname, args, argscall)

FOR_ALL_OPENSSL_FUNCTIONS

Expand All @@ -71,6 +73,7 @@ FOR_ALL_OPENSSL_FUNCTIONS
#undef DEFINEFUNC_3_0
#undef DEFINEFUNC_RENAMED_1_1
#undef DEFINEFUNC_RENAMED_3_0
#undef DEFINEFUNC_VARIADIC_3_0

// go_hash_sum copies ctx into ctx2 and calls EVP_DigestFinal using ctx2.
// This is necessary because Go hash.Hash mandates that Sum has no effect
Expand Down
12 changes: 12 additions & 0 deletions shims.h
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,15 @@ typedef void* GO_SHA_CTX_PTR;
// DEFINEFUNC_RENAMED_3_0 acts like DEFINEFUNC but tries to load the function using the new name when using >= 3.x
// and the old name when using 1.x. In both cases the function will have the new name.
//
// DEFINEFUNC_VARIADIC_3_0 acts like DEFINEFUNC but creates an alias with a more specific signature.
// This is necessary to call variadic functions (functions that accept a variable number of arguments)
// because variadic functions are not directly compatible with cgo. By defining a cgo-compatible alias
// for each desired signature, the C compiler handles the variadic arguments rather than cgo.
// Variadic functions are the only known incompatibility of this kind.
// If you use this macro for a different reason, consider renaming it to something more general first.
// See https://github.com/golang/go/issues/975.
// The process is aborted if the function can't be loaded when using 3.0.0 or higher.
//
// #include <openssl/crypto.h>
// #include <openssl/err.h>
// #include <openssl/rsa.h>
Expand Down Expand Up @@ -298,6 +307,9 @@ DEFINEFUNC(int, EVP_PKEY_paramgen_init, (GO_EVP_PKEY_CTX_PTR ctx), (ctx)) \
DEFINEFUNC(int, EVP_PKEY_paramgen, (GO_EVP_PKEY_CTX_PTR ctx, GO_EVP_PKEY_PTR *ppkey), (ctx, ppkey)) \
DEFINEFUNC(int, EVP_PKEY_keygen_init, (GO_EVP_PKEY_CTX_PTR ctx), (ctx)) \
DEFINEFUNC(int, EVP_PKEY_keygen, (GO_EVP_PKEY_CTX_PTR ctx, GO_EVP_PKEY_PTR *ppkey), (ctx, ppkey)) \
DEFINEFUNC_VARIADIC_3_0(GO_EVP_PKEY_PTR, EVP_PKEY_Q_keygen, EVP_PKEY_Q_keygen, (GO_OSSL_LIB_CTX_PTR ctx, const char *propq, const char *type), (ctx, propq, type)) \
DEFINEFUNC_VARIADIC_3_0(GO_EVP_PKEY_PTR, EVP_PKEY_Q_keygen, EVP_PKEY_Q_keygen_RSA, (GO_OSSL_LIB_CTX_PTR ctx, const char *propq, const char *type, size_t arg1), (ctx, propq, type, arg1)) \
DEFINEFUNC_VARIADIC_3_0(GO_EVP_PKEY_PTR, EVP_PKEY_Q_keygen, EVP_PKEY_Q_keygen_EC, (GO_OSSL_LIB_CTX_PTR ctx, const char *propq, const char *type, const char *arg1), (ctx, propq, type, arg1)) \
DEFINEFUNC(void, EVP_PKEY_CTX_free, (GO_EVP_PKEY_CTX_PTR arg0), (arg0)) \
DEFINEFUNC(int, EVP_PKEY_CTX_ctrl, (GO_EVP_PKEY_CTX_PTR ctx, int keytype, int optype, int cmd, int p1, void *p2), (ctx, keytype, optype, cmd, p1, p2)) \
DEFINEFUNC(int, EVP_PKEY_decrypt, (GO_EVP_PKEY_CTX_PTR arg0, unsigned char *arg1, size_t *arg2, const unsigned char *arg3, size_t arg4), (arg0, arg1, arg2, arg3, arg4)) \
Expand Down

0 comments on commit dd4074a

Please sign in to comment.