Skip to content

Commit 5f850c9

Browse files
committed
implement version check functions in Go using special tags
1 parent 7fa651e commit 5f850c9

23 files changed

+1909
-1113
lines changed

cipher.go

Lines changed: 41 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ func loadCipher(k cipherKind, mode cipherMode) (cipher _EVP_CIPHER_PTR) {
8484
// not created by EVP_CIPHER has negative performance
8585
// implications, as cipher operations will have
8686
// to fetch it on every call. Better to just fetch it once here.
87-
cipher = go_openssl_EVP_CIPHER_fetch(nil, go_openssl_EVP_CIPHER_get0_name(cipher), nil)
87+
cipher, _ = go_openssl_EVP_CIPHER_fetch(nil, go_openssl_EVP_CIPHER_get0_name(cipher), nil)
8888
}
8989
cacheCipher.Store(cacheCipherKey{k, mode}, cipher)
9090
}()
@@ -178,8 +178,8 @@ func (c *evpCipher) encrypt(dst, src []byte) error {
178178
defer go_openssl_EVP_CIPHER_CTX_free(enc_ctx)
179179

180180
var outl int32
181-
if go_openssl_EVP_EncryptUpdate(enc_ctx, base(dst), &outl, base(src), int32(c.blockSize)) != 1 {
182-
return errors.New("EncryptUpdate failed")
181+
if _, err := go_openssl_EVP_EncryptUpdate(enc_ctx, base(dst), &outl, base(src), int32(c.blockSize)); err != nil {
182+
return err
183183
}
184184
runtime.KeepAlive(c)
185185
return nil
@@ -203,8 +203,8 @@ func (c *evpCipher) decrypt(dst, src []byte) error {
203203
}
204204
defer go_openssl_EVP_CIPHER_CTX_free(dec_ctx)
205205

206-
if go_openssl_EVP_CIPHER_CTX_set_padding(dec_ctx, 0) != 1 {
207-
return errors.New("could not disable cipher padding")
206+
if _, err := go_openssl_EVP_CIPHER_CTX_set_padding(dec_ctx, 0); err != nil {
207+
return err
208208
}
209209

210210
var outl int32
@@ -236,19 +236,19 @@ func (x *cipherCBC) CryptBlocks(dst, src []byte) {
236236
}
237237
if len(src) > 0 {
238238
var outl int32
239-
if go_openssl_EVP_CipherUpdate(x.ctx, base(dst), &outl, base(src), int32(len(src))) != 1 {
240-
panic("crypto/cipher: CipherUpdate failed")
239+
if _, err := go_openssl_EVP_CipherUpdate(x.ctx, base(dst), &outl, base(src), int32(len(src))); err != nil {
240+
panic("crypto/cipher: " + err.Error())
241241
}
242242
runtime.KeepAlive(x)
243243
}
244244
}
245245

246246
func (x *cipherCBC) SetIV(iv []byte) {
247247
if len(iv) != x.blockSize {
248-
panic("cipher: incorrect length IV")
248+
panic("crypto/cipher: incorrect length IV")
249249
}
250-
if go_openssl_EVP_CipherInit_ex(x.ctx, nil, nil, nil, base(iv), int32(cipherOpNone)) != 1 {
251-
panic("cipher: unable to initialize EVP cipher ctx")
250+
if _, err := go_openssl_EVP_CipherInit_ex(x.ctx, nil, nil, nil, base(iv), int32(cipherOpNone)); err != nil {
251+
panic("crypto/cipher: " + err.Error())
252252
}
253253
}
254254

@@ -259,8 +259,8 @@ func (c *evpCipher) newCBC(iv []byte, op cipherOp) cipher.BlockMode {
259259
}
260260
x := &cipherCBC{ctx: ctx, blockSize: c.blockSize}
261261
runtime.SetFinalizer(x, (*cipherCBC).finalize)
262-
if go_openssl_EVP_CIPHER_CTX_set_padding(x.ctx, 0) != 1 {
263-
panic("cipher: unable to set padding")
262+
if _, err := go_openssl_EVP_CIPHER_CTX_set_padding(x.ctx, 0); err != nil {
263+
panic("crypto/cipher: " + err.Error())
264264
}
265265
return x
266266
}
@@ -280,8 +280,8 @@ func (x *cipherCTR) XORKeyStream(dst, src []byte) {
280280
return
281281
}
282282
var outl int32
283-
if go_openssl_EVP_EncryptUpdate(x.ctx, base(dst), &outl, base(src), int32(len(src))) != 1 {
284-
panic("crypto/cipher: EncryptUpdate failed")
283+
if _, err := go_openssl_EVP_EncryptUpdate(x.ctx, base(dst), &outl, base(src), int32(len(src))); err != nil {
284+
panic("crypto/cipher: " + err.Error())
285285
}
286286
runtime.KeepAlive(x)
287287
}
@@ -455,22 +455,24 @@ func (g *cipherGCM) Seal(dst, nonce, plaintext, aad []byte) []byte {
455455
// relying in the explicit nonce being securely set externally,
456456
// and it also gives some interesting speed gains.
457457
// Unfortunately we can't use it because Go expects AEAD.Seal to honor the provided nonce.
458-
if go_openssl_EVP_EncryptInit_ex(ctx, nil, nil, nil, base(nonce)) != 1 {
459-
panic(newOpenSSLError("EVP_EncryptInit_ex"))
458+
if _, err := go_openssl_EVP_EncryptInit_ex(ctx, nil, nil, nil, base(nonce)); err != nil {
459+
panic(err)
460460
}
461461
var outl, discard int32
462-
if go_openssl_EVP_EncryptUpdate(ctx, nil, &discard, baseNeverEmpty(aad), int32(len(aad))) != 1 ||
463-
go_openssl_EVP_EncryptUpdate(ctx, base(out), &outl, baseNeverEmpty(plaintext), int32(len(plaintext))) != 1 {
464-
panic(newOpenSSLError("EVP_EncryptUpdate"))
462+
if _, err := go_openssl_EVP_EncryptUpdate(ctx, nil, &discard, baseNeverEmpty(aad), int32(len(aad))); err != nil {
463+
panic(err)
464+
}
465+
if _, err := go_openssl_EVP_EncryptUpdate(ctx, base(out), &outl, baseNeverEmpty(plaintext), int32(len(plaintext))); err != nil {
466+
panic(err)
465467
}
466468
if len(plaintext) != int(outl) {
467469
panic("cipher: incorrect length returned from GCM EncryptUpdate")
468470
}
469-
if go_openssl_EVP_EncryptFinal_ex(ctx, base(out[outl:]), &discard) != 1 {
470-
panic(newOpenSSLError("EVP_EncryptFinal_ex"))
471+
if _, err := go_openssl_EVP_EncryptFinal_ex(ctx, base(out[outl:]), &discard); err != nil {
472+
panic(err)
471473
}
472-
if go_openssl_EVP_CIPHER_CTX_ctrl(ctx, _EVP_CTRL_GCM_GET_TAG, 16, unsafe.Pointer(base(out[outl:]))) != 1 {
473-
panic(newOpenSSLError("EVP_CIPHER_CTX_ctrl"))
474+
if _, err := go_openssl_EVP_CIPHER_CTX_ctrl(ctx, _EVP_CTRL_GCM_GET_TAG, 16, unsafe.Pointer(base(out[outl:]))); err != nil {
475+
panic(err)
474476
}
475477
runtime.KeepAlive(g)
476478
return ret
@@ -515,21 +517,23 @@ func (g *cipherGCM) Open(dst, nonce, ciphertext, aad []byte) (_ []byte, err erro
515517
}
516518
}
517519
}()
518-
if go_openssl_EVP_DecryptInit_ex(ctx, nil, nil, nil, base(nonce)) != 1 {
520+
if _, err := go_openssl_EVP_DecryptInit_ex(ctx, nil, nil, nil, base(nonce)); err != nil {
519521
return nil, errOpen
520522
}
521-
if go_openssl_EVP_CIPHER_CTX_ctrl(ctx, _EVP_CTRL_GCM_SET_TAG, 16, unsafe.Pointer(base(tag))) != 1 {
523+
if _, err := go_openssl_EVP_CIPHER_CTX_ctrl(ctx, _EVP_CTRL_GCM_SET_TAG, 16, unsafe.Pointer(base(tag))); err != nil {
522524
return nil, errOpen
523525
}
524526
var outl, discard int32
525-
if go_openssl_EVP_DecryptUpdate(ctx, nil, &discard, baseNeverEmpty(aad), int32(len(aad))) != 1 ||
526-
go_openssl_EVP_DecryptUpdate(ctx, base(out), &outl, baseNeverEmpty(ciphertext), int32(len(ciphertext))) != 1 {
527+
if _, err := go_openssl_EVP_DecryptUpdate(ctx, nil, &discard, baseNeverEmpty(aad), int32(len(aad))); err != nil {
528+
return nil, errOpen
529+
}
530+
if _, err := go_openssl_EVP_DecryptUpdate(ctx, base(out), &outl, baseNeverEmpty(ciphertext), int32(len(ciphertext))); err != nil {
527531
return nil, errOpen
528532
}
529533
if len(ciphertext) != int(outl) {
530534
return nil, errOpen
531535
}
532-
if go_openssl_EVP_DecryptFinal_ex(ctx, base(out[outl:]), &discard) != 1 {
536+
if _, err := go_openssl_EVP_DecryptFinal_ex(ctx, base(out[outl:]), &discard); err != nil {
533537
return nil, errOpen
534538
}
535539
runtime.KeepAlive(g)
@@ -553,9 +557,9 @@ func newCipherCtx(kind cipherKind, mode cipherMode, encrypt cipherOp, key, iv []
553557
if cipher == nil {
554558
panic("crypto/cipher: unsupported cipher: " + kind.String())
555559
}
556-
ctx := go_openssl_EVP_CIPHER_CTX_new()
557-
if ctx == nil {
558-
return nil, fail("unable to create EVP cipher ctx")
560+
ctx, err := go_openssl_EVP_CIPHER_CTX_new()
561+
if err != nil {
562+
return nil, err
559563
}
560564
defer func() {
561565
if err != nil {
@@ -566,17 +570,17 @@ func newCipherCtx(kind cipherKind, mode cipherMode, encrypt cipherOp, key, iv []
566570
// RC4 cipher supports a variable key length.
567571
// We need to set the key length before setting the key,
568572
// and to do so we need to have an initialized cipher ctx.
569-
if go_openssl_EVP_CipherInit_ex(ctx, cipher, nil, nil, nil, int32(encrypt)) != 1 {
570-
return nil, newOpenSSLError("EVP_CipherInit_ex")
573+
if _, err := go_openssl_EVP_CipherInit_ex(ctx, cipher, nil, nil, nil, int32(encrypt)); err != nil {
574+
return nil, err
571575
}
572-
if go_openssl_EVP_CIPHER_CTX_set_key_length(ctx, int32(len(key))) != 1 {
573-
return nil, newOpenSSLError("EVP_CIPHER_CTX_set_key_length")
576+
if _, err := go_openssl_EVP_CIPHER_CTX_set_key_length(ctx, int32(len(key))); err != nil {
577+
return nil, err
574578
}
575579
// Pass nil to the next call to EVP_CipherInit_ex to avoid resetting ctx's cipher.
576580
cipher = nil
577581
}
578-
if go_openssl_EVP_CipherInit_ex(ctx, cipher, nil, base(key), base(iv), int32(encrypt)) != 1 {
579-
return nil, newOpenSSLError("unable to initialize EVP cipher ctx")
582+
if _, err := go_openssl_EVP_CipherInit_ex(ctx, cipher, nil, base(key), base(iv), int32(encrypt)); err != nil {
583+
return nil, err
580584
}
581585
return ctx, nil
582586
}

cmd/mkcgo/generate.go

Lines changed: 87 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@ func generateGo(src *mkcgo.Source, w io.Writer) {
5454
fmt.Fprintf(w, "}\n\n")
5555
}
5656

57+
typedefs := make(map[string]string, len(src.TypeDefs))
58+
for _, def := range src.TypeDefs {
59+
typedefs[def.Name] = def.Type
60+
}
61+
5762
// Generate function wrappers.
5863
for _, fn := range src.Funcs {
5964
if fn.Variadic() {
@@ -66,7 +71,7 @@ func generateGo(src *mkcgo.Source, w io.Writer) {
6671
fmt.Fprintf(w, "\treturn C.%s_Available() != 0\n", fn.ImportName)
6772
fmt.Fprintf(w, "}\n\n")
6873
}
69-
generateGoFn(fn, w)
74+
generateGoFn(typedefs, fn, w)
7075
}
7176
}
7277

@@ -226,31 +231,75 @@ func generateC(src *mkcgo.Source, w io.Writer) {
226231
}
227232

228233
// generateGoFn generates Go function f.
229-
func generateGoFn(fn *mkcgo.Func, w io.Writer) {
234+
func generateGoFn(typedefs map[string]string, fn *mkcgo.Func, w io.Writer) {
235+
fnCall := fmt.Sprintf("C.%s(%s)", fn.CName, fnToGoArgs(fn))
236+
// Function definition
230237
fmt.Fprintf(w, "func %s(%s)", fn.GoName, fnToGoParams(fn))
231-
if !retIsVoid(fn.Ret) {
232-
fmt.Fprintf(w, " %s ", cTypeToGo(fn.Ret.Type, false))
238+
if retIsVoid(fn.Ret) {
239+
// Easy path, just call the C function. No need to write the return types,
240+
// nor do error handling, nor cast the return value.
241+
fmt.Fprintf(w, "{\n")
242+
fmt.Fprintf(w, "\t%s\n", fnCall)
243+
fmt.Fprintf(w, "}\n\n")
244+
return
245+
}
246+
typ, _ := cTypeToGo(fn.Ret.Type, false)
247+
if fn.NoError {
248+
fmt.Fprintf(w, " %s ", typ)
249+
} else {
250+
fmt.Fprintf(w, " (%s, error) ", typ)
233251
}
234252
fmt.Fprintf(w, "{\n")
235-
fmt.Fprintf(w, "\t")
236-
var closePar int
237-
if !retIsVoid(fn.Ret) {
238-
fmt.Fprintf(w, "return ")
239-
goType := cTypeToGo(fn.Ret.Type, false)
240-
if goType != "" && goType != fn.Ret.Type {
241-
closePar++
242-
if goType[0] == '*' {
243-
goType = fmt.Sprintf("(%s)(unsafe.Pointer", goType)
244-
closePar++
253+
254+
// Function call
255+
var needUnsafeCast bool
256+
goType, needCast := cTypeToGo(fn.Ret.Type, false)
257+
if needCast && goType[0] == '*' {
258+
goType = fmt.Sprintf("(%s)(unsafe.Pointer", goType)
259+
needUnsafeCast = true
260+
}
261+
if fn.NoError {
262+
// No error handling, just cast the return value if necessary.
263+
fmt.Fprintf(w, "\treturn ")
264+
if needCast {
265+
fmt.Fprintf(w, "%s(%s)", goType, fnCall)
266+
if needUnsafeCast {
267+
fmt.Fprintf(w, ")")
245268
}
246-
fmt.Fprintf(w, "%s(", goType)
269+
} else {
270+
fmt.Fprintf(w, "%s", fnCall)
247271
}
272+
fmt.Fprintf(w, "\n")
273+
fmt.Fprintf(w, "}\n\n")
274+
return
248275
}
249-
fmt.Fprintf(w, "C.%s(%s)", fn.CName, fnToGoArgs(fn))
250-
if closePar > 0 {
251-
fmt.Fprint(w, strings.Repeat(")", closePar))
276+
fmt.Fprintf(w, "\t_ret := C.%s(%s)\n", fn.CName, fnToGoArgs(fn))
277+
278+
// Error handling
279+
errCond := "<= 0"
280+
if fn.ErrCond != "" {
281+
errCond = fn.ErrCond
282+
} else if strings.Contains(goType, "unsafe.Pointer") {
283+
errCond = "== nil"
284+
} else if typ, ok := typedefs[goType]; ok && typ == "void*" {
285+
errCond = "== nil"
252286
}
253-
fmt.Fprintf(w, "\n")
287+
fmt.Fprintf(w, "\tvar _err error\n")
288+
fmt.Fprintf(w, "\tif _ret %s {\n", errCond)
289+
fmt.Fprintf(w, "\t\t_err = newOpenSSLError(\"%s\")\n", fn.CName)
290+
fmt.Fprintf(w, "\t}\n")
291+
292+
// Return the value
293+
fmt.Fprintf(w, "\treturn ")
294+
if needCast {
295+
fmt.Fprintf(w, "%s(_ret)", goType)
296+
if needUnsafeCast {
297+
fmt.Fprintf(w, ")")
298+
}
299+
} else {
300+
fmt.Fprintf(w, "_ret")
301+
}
302+
fmt.Fprintf(w, ", _err\n")
254303
fmt.Fprintf(w, "}\n\n")
255304
}
256305

@@ -265,7 +314,10 @@ func generateCFn(fn *mkcgo.Func, w io.Writer) {
265314

266315
// paramToGo converts C parameter p to Go parameter.
267316
func paramToGo(p *mkcgo.Param) string {
268-
goType := cTypeToGo(p.Type, true)
317+
goType, needCast := cTypeToGo(p.Type, true)
318+
if !needCast {
319+
return p.Name
320+
}
269321
switch {
270322
case goType == "unsafe.Pointer" || goType == "":
271323
return p.Name
@@ -318,13 +370,17 @@ var cstdTypesToCgo = map[string]string{
318370
}
319371

320372
// cTypeToGo converts C type t to a Go type.
321-
func cTypeToGo(t string, cgo bool) string {
373+
// If cgo is true, it returns the type that can be
374+
// passed to a cgo function call.
375+
// It returns the Go type and a boolean that reports whether
376+
// the type needs to be casted to goType or not.
377+
func cTypeToGo(t string, cgo bool) (string, bool) {
322378
t, _ = strings.CutPrefix(t, "const ")
323379
if t == "void" {
324-
return ""
380+
return "", true
325381
}
326382
if strings.HasPrefix(t, "void*") {
327-
return "unsafe.Pointer"
383+
return "unsafe.Pointer", false
328384
}
329385
if strings.HasSuffix(t, "*") {
330386
// Remove all trailing '*' characters.
@@ -335,29 +391,25 @@ func cTypeToGo(t string, cgo bool) string {
335391
}
336392
n++
337393
}
338-
s := cTypeToGo(t[:i+1], cgo)
394+
s, std := cTypeToGo(t[:i+1], cgo)
339395
if s != "" {
340396
s = strings.Repeat("*", n) + s
341397
}
342-
return s
398+
return s, std
343399
}
344400
if !isStdType(t) {
345-
if cgo {
346-
// Non-standard C types are aliased so C.<type> so they don't need to be converted.
347-
return ""
348-
}
349-
return t
401+
return t, false
350402
}
351403
if cgo {
352404
if s, ok := cstdTypesToCgo[t]; ok {
353405
t = s
354406
}
355-
return "C." + t
407+
return "C." + t, true
356408
}
357409
if t, ok := cstdTypesToGo[t]; ok {
358-
return t
410+
return t, true
359411
}
360-
return t
412+
return t, true
361413
}
362414

363415
// paramToC returns C source code of parameter p.
@@ -382,7 +434,8 @@ func retIsVoid(r *mkcgo.Return) bool {
382434
// fnToGoParams returns source code for function f parameters.
383435
func fnToGoParams(fn *mkcgo.Func) string {
384436
return join(fn.Params, func(_ int, p *mkcgo.Param) string {
385-
return p.Name + " " + cTypeToGo(p.Type, false)
437+
typ, _ := cTypeToGo(p.Type, false)
438+
return p.Name + " " + typ
386439
}, ", ")
387440
}
388441

0 commit comments

Comments
 (0)