-
Notifications
You must be signed in to change notification settings - Fork 11
/
tls1prf.go
104 lines (98 loc) · 3.29 KB
/
tls1prf.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
//go:build !cmd_go_bootstrap
package openssl
// #include "goopenssl.h"
import "C"
import (
"crypto"
"errors"
"hash"
"unsafe"
)
func SupportsTLS1PRF() bool {
return vMajor > 1 ||
(vMajor >= 1 && vMinor >= 1)
}
// TLS1PRF implements the TLS 1.0/1.1 pseudo-random function if h is nil,
// else it implements the TLS 1.2 pseudo-random function.
// The pseudo-random number will be written to result and will be of length len(result).
func TLS1PRF(result, secret, label, seed []byte, h func() hash.Hash) error {
var md C.GO_EVP_MD_PTR
if h == nil {
// TLS 1.0/1.1 PRF doesn't allow to specify the hash function,
// it always uses MD5SHA1. If h is nil, then assume
// that the caller wants to use TLS 1.0/1.1 PRF.
// OpenSSL detects this case by checking if the hash
// function is MD5SHA1.
md = cryptoHashToMD(crypto.MD5SHA1)
} else {
md = hashToMD(h())
}
if md == nil {
return errors.New("unsupported hash function")
}
ctx := C.go_openssl_EVP_PKEY_CTX_new_id(C.GO_EVP_PKEY_TLS1_PRF, nil)
if ctx == nil {
return newOpenSSLError("EVP_PKEY_CTX_new_id")
}
defer func() {
C.go_openssl_EVP_PKEY_CTX_free(ctx)
}()
if C.go_openssl_EVP_PKEY_derive_init(ctx) != 1 {
return newOpenSSLError("EVP_PKEY_derive_init")
}
switch vMajor {
case 3:
if C.go_openssl_EVP_PKEY_CTX_set_tls1_prf_md(ctx, md) != 1 {
return newOpenSSLError("EVP_PKEY_CTX_set_tls1_prf_md")
}
if C.go_openssl_EVP_PKEY_CTX_set1_tls1_prf_secret(ctx,
base(secret), C.int(len(secret))) != 1 {
return newOpenSSLError("EVP_PKEY_CTX_set1_tls1_prf_secret")
}
if C.go_openssl_EVP_PKEY_CTX_add1_tls1_prf_seed(ctx,
base(label), C.int(len(label))) != 1 {
return newOpenSSLError("EVP_PKEY_CTX_add1_tls1_prf_seed")
}
if C.go_openssl_EVP_PKEY_CTX_add1_tls1_prf_seed(ctx,
base(seed), C.int(len(seed))) != 1 {
return newOpenSSLError("EVP_PKEY_CTX_add1_tls1_prf_seed")
}
case 1:
if C.go_openssl_EVP_PKEY_CTX_ctrl(ctx, -1,
C.GO1_EVP_PKEY_OP_DERIVE,
C.GO_EVP_PKEY_CTRL_TLS_MD,
0, unsafe.Pointer(md)) != 1 {
return newOpenSSLError("EVP_PKEY_CTX_set_tls1_prf_md")
}
if C.go_openssl_EVP_PKEY_CTX_ctrl(ctx, -1,
C.GO1_EVP_PKEY_OP_DERIVE,
C.GO_EVP_PKEY_CTRL_TLS_SECRET,
C.int(len(secret)), unsafe.Pointer(base(secret))) != 1 {
return newOpenSSLError("EVP_PKEY_CTX_set1_tls1_prf_secret")
}
if C.go_openssl_EVP_PKEY_CTX_ctrl(ctx, -1,
C.GO1_EVP_PKEY_OP_DERIVE,
C.GO_EVP_PKEY_CTRL_TLS_SEED,
C.int(len(label)), unsafe.Pointer(base(label))) != 1 {
return newOpenSSLError("EVP_PKEY_CTX_add1_tls1_prf_seed")
}
if C.go_openssl_EVP_PKEY_CTX_ctrl(ctx, -1,
C.GO1_EVP_PKEY_OP_DERIVE,
C.GO_EVP_PKEY_CTRL_TLS_SEED,
C.int(len(seed)), unsafe.Pointer(base(seed))) != 1 {
return newOpenSSLError("EVP_PKEY_CTX_add1_tls1_prf_seed")
}
}
outLen := C.size_t(len(result))
if C.go_openssl_EVP_PKEY_derive_wrapper(ctx, base(result), outLen).result != 1 {
return newOpenSSLError("EVP_PKEY_derive")
}
// The Go standard library expects TLS1PRF to return the requested number of bytes,
// fail if it doesn't. While there is no known situation where this will happen,
// EVP_PKEY_derive handles multiple algorithms and there could be a subtle mismatch
// after more code changes in the future.
if outLen != C.size_t(len(result)) {
return errors.New("tls1-prf: derived less bytes than requested")
}
return nil
}