Skip to content

Commit e9060c6

Browse files
Merge pull request #59 from lealem47/lock_unlock
fips: keep PRIVATE_KEY_UNLOCK/op/LOCK inside a single cgo call
2 parents 978fbed + 4a2c5e2 commit e9060c6

4 files changed

Lines changed: 79 additions & 18 deletions

File tree

aes.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,17 @@ package wolfSSL
115115
// return -174;
116116
// }
117117
// #endif
118+
// /* unlock/op/lock must stay inside one cgo call; see fips.go */
119+
// static int wc_PBKDF2_Unlocked(byte* output, const byte* passwd, int pLen,
120+
// const byte* salt, int sLen, int iterations,
121+
// int kLen, int typeH)
122+
// {
123+
// int ret;
124+
// PRIVATE_KEY_UNLOCK();
125+
// ret = wc_PBKDF2(output, passwd, pLen, salt, sLen, iterations, kLen, typeH);
126+
// PRIVATE_KEY_LOCK();
127+
// return ret;
128+
// }
118129
import "C"
119130
import (
120131
"unsafe"
@@ -274,10 +285,7 @@ func Wc_PBKDF2(out []byte, pwd []byte, pLen int, salt []byte, saltLen int, iter
274285
if len(salt) > 0 {
275286
saltPtr = (*C.uchar)(unsafe.Pointer(&salt[0]))
276287
}
277-
PRIVATE_KEY_UNLOCK()
278-
ret := int(C.wc_PBKDF2(outPtr, pwdPtr, C.int(pLen),
288+
return int(C.wc_PBKDF2_Unlocked(outPtr, pwdPtr, C.int(pLen),
279289
saltPtr, C.int(saltLen), C.int(iter), C.int(kLen), C.int(typeH)))
280-
PRIVATE_KEY_LOCK()
281-
return ret
282290
}
283291

ecc.go

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,35 @@ package wolfSSL
129129
// (void)key; return -174;
130130
// }
131131
// #endif
132+
// /* unlock/op/lock must stay inside one cgo call; see fips.go */
133+
// static int wc_ecc_export_private_only_Unlocked(ecc_key* key, byte* out,
134+
// word32* outLen)
135+
// {
136+
// int ret;
137+
// PRIVATE_KEY_UNLOCK();
138+
// ret = wc_ecc_export_private_only(key, out, outLen);
139+
// PRIVATE_KEY_LOCK();
140+
// return ret;
141+
// }
142+
// static int wc_ecc_export_x963_ex_Unlocked(ecc_key* key, byte* out,
143+
// word32* outLen, int compressed)
144+
// {
145+
// int ret;
146+
// PRIVATE_KEY_UNLOCK();
147+
// ret = wc_ecc_export_x963_ex(key, out, outLen, compressed);
148+
// PRIVATE_KEY_LOCK();
149+
// return ret;
150+
// }
151+
// static int wc_ecc_shared_secret_Unlocked(ecc_key* private_key,
152+
// ecc_key* public_key,
153+
// byte* out, word32* outLen)
154+
// {
155+
// int ret;
156+
// PRIVATE_KEY_UNLOCK();
157+
// ret = wc_ecc_shared_secret(private_key, public_key, out, outLen);
158+
// PRIVATE_KEY_LOCK();
159+
// return ret;
160+
// }
132161
import "C"
133162
import (
134163
"unsafe"
@@ -165,10 +194,8 @@ func Wc_ecc_export_private_only(key *C.struct_ecc_key, out []byte, outLen *int)
165194
return BAD_FUNC_ARG
166195
}
167196
cOutLen := C.word32(*outLen)
168-
PRIVATE_KEY_UNLOCK()
169-
ret := int(C.wc_ecc_export_private_only(key, (*C.byte)(unsafe.Pointer(&out[0])), &cOutLen))
197+
ret := int(C.wc_ecc_export_private_only_Unlocked(key, (*C.byte)(unsafe.Pointer(&out[0])), &cOutLen))
170198
*outLen = int(cOutLen)
171-
PRIVATE_KEY_LOCK()
172199
return ret
173200
}
174201

@@ -177,10 +204,8 @@ func Wc_ecc_export_x963_ex(key *C.struct_ecc_key, out []byte, outLen *int, compr
177204
return BAD_FUNC_ARG
178205
}
179206
cOutLen := C.word32(*outLen)
180-
PRIVATE_KEY_UNLOCK()
181-
ret := int(C.wc_ecc_export_x963_ex(key, (*C.byte)(unsafe.Pointer(&out[0])), &cOutLen, C.int(compressed)))
207+
ret := int(C.wc_ecc_export_x963_ex_Unlocked(key, (*C.byte)(unsafe.Pointer(&out[0])), &cOutLen, C.int(compressed)))
182208
*outLen = int(cOutLen)
183-
PRIVATE_KEY_LOCK()
184209
return ret
185210
}
186211

@@ -254,10 +279,8 @@ func Wc_ecc_shared_secret(privKey, pubKey *C.struct_ecc_key, out []byte, outLen
254279
return BAD_FUNC_ARG
255280
}
256281
cOutLen := C.word32(*outLen)
257-
PRIVATE_KEY_UNLOCK()
258-
ret := int(C.wc_ecc_shared_secret(privKey, pubKey, (*C.uchar)(unsafe.Pointer(&out[0])), &cOutLen))
282+
ret := int(C.wc_ecc_shared_secret_Unlocked(privKey, pubKey, (*C.uchar)(unsafe.Pointer(&out[0])), &cOutLen))
259283
*outLen = int(cOutLen)
260-
PRIVATE_KEY_LOCK()
261284
return ret
262285
}
263286

fips.go

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ package wolfSSL
3030
// return -174;
3131
// }
3232
// #endif
33-
// #define WC_SPKRE_F(x,y) wolfCrypt_SetPrivateKeyReadEnable_fips((x),(y))
3433
// #ifdef HAVE_FIPS
3534
// int WC_PRIVATE_KEY_LOCK(void) {
3635
// return WC_SPKRE_F(0,WC_KEYTYPE_ALL);
@@ -76,10 +75,32 @@ func Wc_SetDefaultSeed_Cb() int {
7675
return int(C.wc_SetSeed_Cb((C.wc_RngSeed_Cb)(C.wc_GenerateSeed)))
7776
}
7877

78+
// FIPS private-key gate.
79+
//
80+
// wolfCrypt's FIPS APIs refuse to read private-key material unless the
81+
// calling thread has enabled it. In userspace builds that enable flag is
82+
// per-OS-thread instead of process-wide.
83+
//
84+
// A goroutine is pinned to its OS thread only for the duration of a single
85+
// cgo call. Calling PRIVATE_KEY_UNLOCK, then the wolfCrypt operation, then
86+
// PRIVATE_KEY_LOCK as three separate cgo calls therefore leaves a window in
87+
// which the scheduler can move the goroutine to another thread. The
88+
// operation then runs on a thread whose counter was never incremented and
89+
// fails with FIPS_PRIVATE_KEY_LOCKED_E (-287), while the thread that took
90+
// the unlock is left permanently unlocked.
91+
//
92+
// The Wc_* wrappers in this go-wolfssl avoid that by performing unlock,
93+
// operation and lock inside one static C helper (wc_HKDF_Unlocked,
94+
// wc_PBKDF2_Unlocked, ...).
95+
//
96+
// PRIVATE_KEY_LOCK and PRIVATE_KEY_UNLOCK are exported but they act on the
97+
// calling OS thread's counter, so any direct callers must hold
98+
// runtime.LockOSThread() across the entire unlock/operation/lock sequence.
7999
func PRIVATE_KEY_LOCK() int {
80100
return int(C.WC_PRIVATE_KEY_LOCK())
81101
}
82102

103+
// See PRIVATE_KEY_LOCK for the threading requirements.
83104
func PRIVATE_KEY_UNLOCK() int {
84105
return int(C.WC_PRIVATE_KEY_UNLOCK())
85106
}

hmac.go

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,18 @@ package wolfSSL
4545
// free(ptr);
4646
// }
4747
// #endif
48+
// /* unlock/op/lock must stay inside one cgo call; see fips.go */
49+
// static int wc_HKDF_Unlocked(int type, const byte* inKey, word32 inKeySz,
50+
// const byte* salt, word32 saltSz,
51+
// const byte* info, word32 infoSz,
52+
// byte* out, word32 outSz)
53+
// {
54+
// int ret;
55+
// PRIVATE_KEY_UNLOCK();
56+
// ret = wc_HKDF(type, inKey, inKeySz, salt, saltSz, info, infoSz, out, outSz);
57+
// PRIVATE_KEY_LOCK();
58+
// return ret;
59+
// }
4860
import "C"
4961
import (
5062
"unsafe"
@@ -119,12 +131,9 @@ func Wc_HKDF(hashType int, inputKey []byte, inputKeySz int, salt []byte,
119131
if len(info) > 0 {
120132
infoPtr = (*C.uchar)(unsafe.Pointer(&info[0]))
121133
}
122-
PRIVATE_KEY_UNLOCK()
123-
ret := int(C.wc_HKDF(C.int(hashType), ikmPtr,
134+
return int(C.wc_HKDF_Unlocked(C.int(hashType), ikmPtr,
124135
C.word32(inputKeySz), saltPtr,
125136
C.word32(saltSz), infoPtr,
126137
C.word32(infoSz), (*C.uchar)(unsafe.Pointer(&out[0])),
127138
C.word32(outSz)))
128-
PRIVATE_KEY_LOCK()
129-
return ret
130139
}

0 commit comments

Comments
 (0)