Skip to content

Commit dd4074a

Browse files
qmuntaldagood
andauthored
Generate PKEYs using EVP_PKEY_Q_keygen (#229)
* 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]>
1 parent bdc3592 commit dd4074a

File tree

6 files changed

+75
-24
lines changed

6 files changed

+75
-24
lines changed

cmd/checkheader/main.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,11 @@ func tryConvertDefineFunc(w io.Writer, l string, i int) bool {
227227
if !strings.HasPrefix(l, "DEFINEFUNC") {
228228
return false
229229
}
230+
if strings.HasPrefix(l, "DEFINEFUNC_VARIADIC") {
231+
// Variadic functions are not supported. There is not enough
232+
// information in the macro to create use it in writeDefineFunc.
233+
return false
234+
}
230235
i1 := strings.IndexByte(l, '(')
231236
// The first ")," match is always the end of the argument list parameter.
232237
// We are not interested in the last parameter and parsing them would complicate the algorithm.

ed25519.go

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import (
99
"runtime"
1010
"strconv"
1111
"sync"
12-
"unsafe"
1312
)
1413

1514
const (
@@ -37,9 +36,7 @@ var supportsEd25519 = sync.OnceValue(func() bool {
3736
}
3837
}
3938
case 3:
40-
name := C.CString("ED25519")
41-
defer C.free(unsafe.Pointer(name))
42-
sig := C.go_openssl_EVP_SIGNATURE_fetch(nil, name, nil)
39+
sig := C.go_openssl_EVP_SIGNATURE_fetch(nil, keyTypeED25519, nil)
4340
if sig != nil {
4441
C.go_openssl_EVP_SIGNATURE_free(sig)
4542
return true

evp.go

Lines changed: 46 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@ import (
1313
"unsafe"
1414
)
1515

16+
var (
17+
keyTypeRSA = C.CString("RSA")
18+
keyTypeEC = C.CString("EC")
19+
keyTypeED25519 = C.CString("ED25519")
20+
)
21+
1622
// cacheMD is a cache of crypto.Hash to GO_EVP_MD_PTR.
1723
var cacheMD sync.Map
1824

@@ -157,33 +163,53 @@ func cryptoHashToMD(ch crypto.Hash) (md C.GO_EVP_MD_PTR) {
157163
return nil
158164
}
159165

166+
// generateEVPPKey generates a new EVP_PKEY with the given id and properties.
160167
func generateEVPPKey(id C.int, bits int, curve string) (C.GO_EVP_PKEY_PTR, error) {
161168
if bits != 0 && curve != "" {
162169
return nil, fail("incorrect generateEVPPKey parameters")
163170
}
164-
ctx := C.go_openssl_EVP_PKEY_CTX_new_id(id, nil)
165-
if ctx == nil {
166-
return nil, newOpenSSLError("EVP_PKEY_CTX_new_id failed")
167-
}
168-
defer C.go_openssl_EVP_PKEY_CTX_free(ctx)
169-
if C.go_openssl_EVP_PKEY_keygen_init(ctx) != 1 {
170-
return nil, newOpenSSLError("EVP_PKEY_keygen_init failed")
171-
}
172-
if bits != 0 {
173-
if C.go_openssl_EVP_PKEY_CTX_ctrl(ctx, id, -1, C.GO_EVP_PKEY_CTRL_RSA_KEYGEN_BITS, C.int(bits), nil) != 1 {
174-
return nil, newOpenSSLError("EVP_PKEY_CTX_ctrl failed")
171+
var pkey C.GO_EVP_PKEY_PTR
172+
switch vMajor {
173+
case 1:
174+
ctx := C.go_openssl_EVP_PKEY_CTX_new_id(id, nil)
175+
if ctx == nil {
176+
return nil, newOpenSSLError("EVP_PKEY_CTX_new_id")
177+
}
178+
defer C.go_openssl_EVP_PKEY_CTX_free(ctx)
179+
if C.go_openssl_EVP_PKEY_keygen_init(ctx) != 1 {
180+
return nil, newOpenSSLError("EVP_PKEY_keygen_init")
181+
}
182+
if bits != 0 {
183+
if C.go_openssl_EVP_PKEY_CTX_ctrl(ctx, id, -1, C.GO_EVP_PKEY_CTRL_RSA_KEYGEN_BITS, C.int(bits), nil) != 1 {
184+
return nil, newOpenSSLError("EVP_PKEY_CTX_ctrl")
185+
}
175186
}
176-
}
177-
if curve != "" {
178-
nid := curveNID(curve)
179-
if C.go_openssl_EVP_PKEY_CTX_ctrl(ctx, id, -1, C.GO_EVP_PKEY_CTRL_EC_PARAMGEN_CURVE_NID, nid, nil) != 1 {
180-
return nil, newOpenSSLError("EVP_PKEY_CTX_ctrl failed")
187+
if curve != "" {
188+
if C.go_openssl_EVP_PKEY_CTX_ctrl(ctx, id, -1, C.GO_EVP_PKEY_CTRL_EC_PARAMGEN_CURVE_NID, curveNID(curve), nil) != 1 {
189+
return nil, newOpenSSLError("EVP_PKEY_CTX_ctrl")
190+
}
181191
}
192+
if C.go_openssl_EVP_PKEY_keygen(ctx, &pkey) != 1 {
193+
return nil, newOpenSSLError("EVP_PKEY_keygen")
194+
}
195+
case 3:
196+
switch id {
197+
case C.GO_EVP_PKEY_RSA:
198+
pkey = C.go_openssl_EVP_PKEY_Q_keygen_RSA(nil, nil, keyTypeRSA, C.size_t(bits))
199+
case C.GO_EVP_PKEY_EC:
200+
pkey = C.go_openssl_EVP_PKEY_Q_keygen_EC(nil, nil, keyTypeEC, C.go_openssl_OBJ_nid2sn(curveNID(curve)))
201+
case C.GO_EVP_PKEY_ED25519:
202+
pkey = C.go_openssl_EVP_PKEY_Q_keygen(nil, nil, keyTypeED25519)
203+
default:
204+
panic("unsupported key type '" + strconv.Itoa(int(id)) + "'")
205+
}
206+
if pkey == nil {
207+
return nil, newOpenSSLError("EVP_PKEY_Q_keygen")
208+
}
209+
default:
210+
panic(errUnsupportedVersion())
182211
}
183-
var pkey C.GO_EVP_PKEY_PTR
184-
if C.go_openssl_EVP_PKEY_keygen(ctx, &pkey) != 1 {
185-
return nil, newOpenSSLError("EVP_PKEY_keygen failed")
186-
}
212+
187213
return pkey, nil
188214
}
189215

goopenssl.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#define DEFINEFUNC_3_0(ret, func, args, argscall) DEFINEFUNC(ret, func, args, argscall)
2323
#define DEFINEFUNC_RENAMED_1_1(ret, func, oldfunc, args, argscall) DEFINEFUNC(ret, func, args, argscall)
2424
#define DEFINEFUNC_RENAMED_3_0(ret, func, oldfunc, args, argscall) DEFINEFUNC(ret, func, args, argscall)
25+
#define DEFINEFUNC_VARIADIC_3_0(ret, func, newname, args, argscall) DEFINEFUNC(ret, newname, args, argscall)
2526

2627
FOR_ALL_OPENSSL_FUNCTIONS
2728

@@ -34,6 +35,7 @@ FOR_ALL_OPENSSL_FUNCTIONS
3435
#undef DEFINEFUNC_3_0
3536
#undef DEFINEFUNC_RENAMED_1_1
3637
#undef DEFINEFUNC_RENAMED_3_0
38+
#undef DEFINEFUNC_VARIADIC_3_0
3739

3840
// go_openssl_fips_enabled returns 1 if FIPS mode is enabled, 0 otherwise.
3941
// As a special case, it returns -1 if it cannot determine if FIPS mode is enabled.
@@ -140,6 +142,11 @@ go_openssl_load_functions(void* handle, unsigned int major, unsigned int minor,
140142
{ \
141143
DEFINEFUNC_INTERNAL(func, #func) \
142144
}
145+
#define DEFINEFUNC_VARIADIC_3_0(ret, func, newname, args, argscall) \
146+
if (major == 3) \
147+
{ \
148+
DEFINEFUNC_INTERNAL(newname, #func) \
149+
}
143150

144151
FOR_ALL_OPENSSL_FUNCTIONS
145152

@@ -152,6 +159,7 @@ FOR_ALL_OPENSSL_FUNCTIONS
152159
#undef DEFINEFUNC_3_0
153160
#undef DEFINEFUNC_RENAMED_1_1
154161
#undef DEFINEFUNC_RENAMED_3_0
162+
#undef DEFINEFUNC_VARIADIC_3_0
155163
}
156164

157165
static unsigned long

goopenssl.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ int go_openssl_DSA_set0_key_backport(GO_DSA_PTR d, GO_BIGNUM_PTR pub_key, GO_BIG
5959
DEFINEFUNC(ret, func, args, argscall)
6060
#define DEFINEFUNC_RENAMED_3_0(ret, func, oldfunc, args, argscall) \
6161
DEFINEFUNC(ret, func, args, argscall)
62+
#define DEFINEFUNC_VARIADIC_3_0(ret, func, newname, args, argscall) \
63+
DEFINEFUNC(ret, newname, args, argscall)
6264

6365
FOR_ALL_OPENSSL_FUNCTIONS
6466

@@ -71,6 +73,7 @@ FOR_ALL_OPENSSL_FUNCTIONS
7173
#undef DEFINEFUNC_3_0
7274
#undef DEFINEFUNC_RENAMED_1_1
7375
#undef DEFINEFUNC_RENAMED_3_0
76+
#undef DEFINEFUNC_VARIADIC_3_0
7477

7578
// go_hash_sum copies ctx into ctx2 and calls EVP_DigestFinal using ctx2.
7679
// This is necessary because Go hash.Hash mandates that Sum has no effect

shims.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,15 @@ typedef void* GO_SHA_CTX_PTR;
157157
// DEFINEFUNC_RENAMED_3_0 acts like DEFINEFUNC but tries to load the function using the new name when using >= 3.x
158158
// and the old name when using 1.x. In both cases the function will have the new name.
159159
//
160+
// DEFINEFUNC_VARIADIC_3_0 acts like DEFINEFUNC but creates an alias with a more specific signature.
161+
// This is necessary to call variadic functions (functions that accept a variable number of arguments)
162+
// because variadic functions are not directly compatible with cgo. By defining a cgo-compatible alias
163+
// for each desired signature, the C compiler handles the variadic arguments rather than cgo.
164+
// Variadic functions are the only known incompatibility of this kind.
165+
// If you use this macro for a different reason, consider renaming it to something more general first.
166+
// See https://github.com/golang/go/issues/975.
167+
// The process is aborted if the function can't be loaded when using 3.0.0 or higher.
168+
//
160169
// #include <openssl/crypto.h>
161170
// #include <openssl/err.h>
162171
// #include <openssl/rsa.h>
@@ -298,6 +307,9 @@ DEFINEFUNC(int, EVP_PKEY_paramgen_init, (GO_EVP_PKEY_CTX_PTR ctx), (ctx)) \
298307
DEFINEFUNC(int, EVP_PKEY_paramgen, (GO_EVP_PKEY_CTX_PTR ctx, GO_EVP_PKEY_PTR *ppkey), (ctx, ppkey)) \
299308
DEFINEFUNC(int, EVP_PKEY_keygen_init, (GO_EVP_PKEY_CTX_PTR ctx), (ctx)) \
300309
DEFINEFUNC(int, EVP_PKEY_keygen, (GO_EVP_PKEY_CTX_PTR ctx, GO_EVP_PKEY_PTR *ppkey), (ctx, ppkey)) \
310+
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)) \
311+
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)) \
312+
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)) \
301313
DEFINEFUNC(void, EVP_PKEY_CTX_free, (GO_EVP_PKEY_CTX_PTR arg0), (arg0)) \
302314
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)) \
303315
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)) \

0 commit comments

Comments
 (0)