1// Copyright 2017 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5//go:build boringcrypto && linux && (amd64 || arm64) && !android && !msan
6
7package boring
8
9/*
10// goboringcrypto_linux_amd64.syso references pthread functions.
11#cgo LDFLAGS: "-pthread"
12
13#include "goboringcrypto.h"
14*/
15import "C"
16import (
17	"crypto/internal/boring/sig"
18	_ "crypto/internal/boring/syso"
19	"internal/stringslite"
20	"math/bits"
21	"unsafe"
22)
23
24const available = true
25
26func init() {
27	C._goboringcrypto_BORINGSSL_bcm_power_on_self_test()
28	if C._goboringcrypto_FIPS_mode() != 1 {
29		panic("boringcrypto: not in FIPS mode")
30	}
31	sig.BoringCrypto()
32}
33
34// Unreachable marks code that should be unreachable
35// when BoringCrypto is in use. It panics.
36func Unreachable() {
37	panic("boringcrypto: invalid code execution")
38}
39
40// provided by runtime to avoid os import.
41func runtime_arg0() string
42
43// UnreachableExceptTests marks code that should be unreachable
44// when BoringCrypto is in use. It panics.
45func UnreachableExceptTests() {
46	name := runtime_arg0()
47	// If BoringCrypto ran on Windows we'd need to allow _test.exe and .test.exe as well.
48	if !stringslite.HasSuffix(name, "_test") && !stringslite.HasSuffix(name, ".test") {
49		println("boringcrypto: unexpected code execution in", name)
50		panic("boringcrypto: invalid code execution")
51	}
52}
53
54type fail string
55
56func (e fail) Error() string { return "boringcrypto: " + string(e) + " failed" }
57
58func wbase(b BigInt) *C.uint8_t {
59	if len(b) == 0 {
60		return nil
61	}
62	return (*C.uint8_t)(unsafe.Pointer(&b[0]))
63}
64
65const wordBytes = bits.UintSize / 8
66
67func bigToBN(x BigInt) *C.GO_BIGNUM {
68	return C._goboringcrypto_BN_le2bn(wbase(x), C.size_t(len(x)*wordBytes), nil)
69}
70
71func bytesToBN(x []byte) *C.GO_BIGNUM {
72	return C._goboringcrypto_BN_bin2bn((*C.uint8_t)(&x[0]), C.size_t(len(x)), nil)
73}
74
75func bnToBig(bn *C.GO_BIGNUM) BigInt {
76	x := make(BigInt, (C._goboringcrypto_BN_num_bytes(bn)+wordBytes-1)/wordBytes)
77	if C._goboringcrypto_BN_bn2le_padded(wbase(x), C.size_t(len(x)*wordBytes), bn) == 0 {
78		panic("boringcrypto: bignum conversion failed")
79	}
80	return x
81}
82
83func bigToBn(bnp **C.GO_BIGNUM, b BigInt) bool {
84	if *bnp != nil {
85		C._goboringcrypto_BN_free(*bnp)
86		*bnp = nil
87	}
88	if b == nil {
89		return true
90	}
91	bn := bigToBN(b)
92	if bn == nil {
93		return false
94	}
95	*bnp = bn
96	return true
97}
98
99// noescape hides a pointer from escape analysis.  noescape is
100// the identity function but escape analysis doesn't think the
101// output depends on the input.  noescape is inlined and currently
102// compiles down to zero instructions.
103// USE CAREFULLY!
104//
105//go:nosplit
106func noescape(p unsafe.Pointer) unsafe.Pointer {
107	x := uintptr(p)
108	return unsafe.Pointer(x ^ 0)
109}
110
111var zero byte
112
113// addr converts p to its base addr, including a noescape along the way.
114// If p is nil, addr returns a non-nil pointer, so that the result can always
115// be dereferenced.
116//
117//go:nosplit
118func addr(p []byte) *byte {
119	if len(p) == 0 {
120		return &zero
121	}
122	return (*byte)(noescape(unsafe.Pointer(&p[0])))
123}
124