1+ // Copyright (c) Microsoft Corporation. All rights reserved.
2+ // Licensed under the Apache 2.0 License.
3+ #pragma once
4+
5+ #include " ds/logger.h"
6+ #include " tls.h"
7+
8+ #include < secp256k1/include/secp256k1.h>
9+ #include < secp256k1/include/secp256k1_recovery.h>
10+ #include < stdexcept>
11+ #include < string>
12+
13+ namespace tls
14+ {
15+ enum class CurveImpl
16+ {
17+ secp384r1 = 1 ,
18+ #ifdef MOD_MBEDTLS
19+ ed25519 = 2 ,
20+ #endif
21+ secp256k1_mbedtls = 3 ,
22+ secp256k1_bitcoin = 4 ,
23+
24+ #if SERVICE_IDENTITY_CURVE_CHOICE_SECP384R1
25+ service_identity_curve_choice = secp384r1,
26+ #elif SERVICE_IDENTITY_CURVE_CHOICE_ED25519
27+ service_identity_curve_choice = ed25519,
28+ #elif SERVICE_IDENTITY_CURVE_CHOICE_SECP256K1_MBEDTLS
29+ service_identity_curve_choice = secp256k1_mbedtls,
30+ #elif SERVICE_IDENTITY_CURVE_CHOICE_SECP256K1_BITCOIN
31+ service_identity_curve_choice = secp256k1_bitcoin,
32+ #else
33+ # pragma message( \
34+ " No service identity curve specified - defaulting to secp384r1" )
35+ service_identity_curve_choice = secp384r1,
36+ #endif
37+ };
38+
39+ // 2 implementations of secp256k1 are available - mbedtls and bitcoin. Either
40+ // can be asked for explicitly via the CurveImpl enum. For cases where we
41+ // receive a raw 256k1 key/signature/cert only, this flag determines which
42+ // implementation is used
43+ static constexpr bool prefer_bitcoin_secp256k1 = true ;
44+
45+ // Helper to access elliptic curve id from context
46+ inline mbedtls_ecp_group_id get_ec_from_context (const mbedtls_pk_context& ctx)
47+ {
48+ return mbedtls_pk_ec (ctx)->grp .id ;
49+ }
50+
51+ // Get mbedtls elliptic curve for given CCF curve implementation
52+ inline mbedtls_ecp_group_id get_ec_for_curve_impl (CurveImpl curve)
53+ {
54+ switch (curve)
55+ {
56+ case CurveImpl::secp384r1:
57+ {
58+ return MBEDTLS_ECP_DP_SECP384R1;
59+ }
60+ #ifdef MOD_MBEDTLS
61+ case CurveImpl::ed25519:
62+ {
63+ return MBEDTLS_ECP_DP_CURVE25519;
64+ }
65+ #endif
66+ case CurveImpl::secp256k1_mbedtls:
67+ case CurveImpl::secp256k1_bitcoin:
68+ {
69+ return MBEDTLS_ECP_DP_SECP256K1;
70+ }
71+ default :
72+ {
73+ throw std::logic_error (
74+ " Unhandled curve type: " +
75+ std::to_string (static_cast <size_t >(curve)));
76+ }
77+ }
78+ }
79+
80+ // Get message digest algorithm to use for given elliptic curve
81+ inline mbedtls_md_type_t get_md_for_ec (mbedtls_ecp_group_id ec)
82+ {
83+ switch (ec)
84+ {
85+ case MBEDTLS_ECP_DP_SECP384R1:
86+ {
87+ return MBEDTLS_MD_SHA384;
88+ }
89+ #ifdef MOD_MBEDTLS
90+ case MBEDTLS_ECP_DP_CURVE25519:
91+ {
92+ return MBEDTLS_MD_SHA512;
93+ }
94+ #endif
95+ case MBEDTLS_ECP_DP_SECP256K1:
96+ {
97+ return MBEDTLS_MD_SHA256;
98+ }
99+ default :
100+ {
101+ throw std::logic_error (
102+ std::string (" Unhandled ecp group id: " ) +
103+ mbedtls_ecp_curve_info_from_grp_id (ec)->name );
104+ }
105+ }
106+ }
107+
108+ inline bool verify_secp256k_bc (
109+ secp256k1_context* ctx,
110+ const uint8_t * signature,
111+ size_t signature_size,
112+ const uint8_t * hash,
113+ size_t hash_size,
114+ const secp256k1_pubkey* public_key)
115+ {
116+ if (hash_size != 32 )
117+ return false ;
118+
119+ secp256k1_ecdsa_signature sig;
120+ if (
121+ secp256k1_ecdsa_signature_parse_der (
122+ ctx, &sig, signature, signature_size) != 1 )
123+ return false ;
124+
125+ secp256k1_ecdsa_signature norm_sig;
126+ if (secp256k1_ecdsa_signature_normalize (ctx, &norm_sig, &sig) == 1 )
127+ {
128+ LOG_TRACE_FMT (" secp256k1 normalized a signature to lower-S form" );
129+ }
130+
131+ return secp256k1_ecdsa_verify (ctx, &norm_sig, hash, public_key) == 1 ;
132+ }
133+
134+ static void secp256k1_illegal_callback (const char * str, void *)
135+ {
136+ throw std::logic_error (
137+ fmt::format (" [libsecp256k1] illegal argument: {}" , str));
138+ }
139+
140+ // Wrap calls to secp256k1_context_create, setting illegal callback to throw
141+ // catchable errors rather than aborting, and ensuring destroy is called when
142+ // this goes out of scope
143+ class BCk1Context
144+ {
145+ public:
146+ secp256k1_context* p = nullptr ;
147+
148+ BCk1Context (unsigned int flags)
149+ {
150+ p = secp256k1_context_create (flags);
151+
152+ secp256k1_context_set_illegal_callback (
153+ p, secp256k1_illegal_callback, nullptr );
154+ }
155+
156+ ~BCk1Context ()
157+ {
158+ secp256k1_context_destroy (p);
159+ }
160+ };
161+
162+ using BCk1ContextPtr = std::unique_ptr<BCk1Context>;
163+
164+ inline BCk1ContextPtr make_bc_context (unsigned int flags)
165+ {
166+ return std::make_unique<BCk1Context>(flags);
167+ }
168+ }
0 commit comments