xref: /aosp_15_r20/external/open-dice/third_party/cose-c/cose_deps.cc (revision 60b67249c2e226f42f35cc6cfe66c6048e0bae6b)
1*60b67249SAndroid Build Coastguard Worker // Copyright 2024 Google LLC
2*60b67249SAndroid Build Coastguard Worker //
3*60b67249SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4*60b67249SAndroid Build Coastguard Worker // use this file except in compliance with the License. You may obtain a copy of
5*60b67249SAndroid Build Coastguard Worker // the License at
6*60b67249SAndroid Build Coastguard Worker //
7*60b67249SAndroid Build Coastguard Worker //     https://www.apache.org/licenses/LICENSE-2.0
8*60b67249SAndroid Build Coastguard Worker //
9*60b67249SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*60b67249SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11*60b67249SAndroid Build Coastguard Worker // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12*60b67249SAndroid Build Coastguard Worker // License for the specific language governing permissions and limitations under
13*60b67249SAndroid Build Coastguard Worker // the License.
14*60b67249SAndroid Build Coastguard Worker 
15*60b67249SAndroid Build Coastguard Worker #include <stdint.h>
16*60b67249SAndroid Build Coastguard Worker #include <string.h>
17*60b67249SAndroid Build Coastguard Worker 
18*60b67249SAndroid Build Coastguard Worker #include <optional>
19*60b67249SAndroid Build Coastguard Worker 
20*60b67249SAndroid Build Coastguard Worker #include "cose/cose.h"
21*60b67249SAndroid Build Coastguard Worker #include "cose/cose_configure.h"
22*60b67249SAndroid Build Coastguard Worker #include "cose_int.h"
23*60b67249SAndroid Build Coastguard Worker #include "openssl/bn.h"
24*60b67249SAndroid Build Coastguard Worker #include "openssl/curve25519.h"
25*60b67249SAndroid Build Coastguard Worker #include "openssl/ec.h"
26*60b67249SAndroid Build Coastguard Worker #include "openssl/ec_key.h"
27*60b67249SAndroid Build Coastguard Worker #include "openssl/ecdsa.h"
28*60b67249SAndroid Build Coastguard Worker #include "openssl/evp.h"
29*60b67249SAndroid Build Coastguard Worker #include "openssl/is_boringssl.h"
30*60b67249SAndroid Build Coastguard Worker #include "openssl/sha.h"
31*60b67249SAndroid Build Coastguard Worker 
32*60b67249SAndroid Build Coastguard Worker namespace {
33*60b67249SAndroid Build Coastguard Worker 
34*60b67249SAndroid Build Coastguard Worker // Checks the type and ops have the expected values.
CheckCoseKeyTypeAndOps(const cn_cbor * key,uint64_t expected_type)35*60b67249SAndroid Build Coastguard Worker bool CheckCoseKeyTypeAndOps(const cn_cbor *key, uint64_t expected_type) {
36*60b67249SAndroid Build Coastguard Worker   const int64_t kCoseKeyOpsLabel = 4;
37*60b67249SAndroid Build Coastguard Worker   const uint64_t kCoseKeyOpsVerify = 2;
38*60b67249SAndroid Build Coastguard Worker 
39*60b67249SAndroid Build Coastguard Worker   cn_cbor *type = cn_cbor_mapget_int(key, COSE_Key_Type);
40*60b67249SAndroid Build Coastguard Worker   if (!type) {
41*60b67249SAndroid Build Coastguard Worker     return false;
42*60b67249SAndroid Build Coastguard Worker   }
43*60b67249SAndroid Build Coastguard Worker   if (type->type != CN_CBOR_UINT || type->v.uint != expected_type) {
44*60b67249SAndroid Build Coastguard Worker     return false;
45*60b67249SAndroid Build Coastguard Worker   }
46*60b67249SAndroid Build Coastguard Worker 
47*60b67249SAndroid Build Coastguard Worker   cn_cbor *ops = cn_cbor_mapget_int(key, kCoseKeyOpsLabel);
48*60b67249SAndroid Build Coastguard Worker   if (ops) {
49*60b67249SAndroid Build Coastguard Worker     if (ops->type != CN_CBOR_ARRAY || ops->length == 0) {
50*60b67249SAndroid Build Coastguard Worker       return false;
51*60b67249SAndroid Build Coastguard Worker     }
52*60b67249SAndroid Build Coastguard Worker     bool found_verify = false;
53*60b67249SAndroid Build Coastguard Worker     for (size_t i = 0; i < ops->length; ++i) {
54*60b67249SAndroid Build Coastguard Worker       cn_cbor *item = cn_cbor_index(ops, i);
55*60b67249SAndroid Build Coastguard Worker       if (!item || item->type != CN_CBOR_UINT) {
56*60b67249SAndroid Build Coastguard Worker         return false;
57*60b67249SAndroid Build Coastguard Worker       }
58*60b67249SAndroid Build Coastguard Worker       if (item->v.uint == kCoseKeyOpsVerify) {
59*60b67249SAndroid Build Coastguard Worker         found_verify = true;
60*60b67249SAndroid Build Coastguard Worker       }
61*60b67249SAndroid Build Coastguard Worker     }
62*60b67249SAndroid Build Coastguard Worker     if (!found_verify) {
63*60b67249SAndroid Build Coastguard Worker       return false;
64*60b67249SAndroid Build Coastguard Worker     }
65*60b67249SAndroid Build Coastguard Worker   }
66*60b67249SAndroid Build Coastguard Worker   return true;
67*60b67249SAndroid Build Coastguard Worker }
68*60b67249SAndroid Build Coastguard Worker 
69*60b67249SAndroid Build Coastguard Worker // Checks that the optional algorithm field is the expected value.
CheckCoseKeyAlg(const cn_cbor * key,int64_t expected_alg)70*60b67249SAndroid Build Coastguard Worker bool CheckCoseKeyAlg(const cn_cbor *key, int64_t expected_alg) {
71*60b67249SAndroid Build Coastguard Worker   const int64_t kCoseKeyAlgLabel = 3;
72*60b67249SAndroid Build Coastguard Worker 
73*60b67249SAndroid Build Coastguard Worker   cn_cbor *alg = cn_cbor_mapget_int(key, kCoseKeyAlgLabel);
74*60b67249SAndroid Build Coastguard Worker   if (alg) {
75*60b67249SAndroid Build Coastguard Worker     if (alg->type != CN_CBOR_INT || alg->v.sint != expected_alg) {
76*60b67249SAndroid Build Coastguard Worker       return false;
77*60b67249SAndroid Build Coastguard Worker     }
78*60b67249SAndroid Build Coastguard Worker   }
79*60b67249SAndroid Build Coastguard Worker   return true;
80*60b67249SAndroid Build Coastguard Worker }
81*60b67249SAndroid Build Coastguard Worker 
82*60b67249SAndroid Build Coastguard Worker // Gets the public key from a well-formed EC2 COSE_Key.
GetEcKey(cn_cbor * key,int nid,size_t coord_size)83*60b67249SAndroid Build Coastguard Worker std::optional<bssl::UniquePtr<EC_KEY>> GetEcKey(cn_cbor *key, int nid,
84*60b67249SAndroid Build Coastguard Worker                                                 size_t coord_size) {
85*60b67249SAndroid Build Coastguard Worker   cn_cbor *raw_x = cn_cbor_mapget_int(key, COSE_Key_EC2_X);
86*60b67249SAndroid Build Coastguard Worker   if (!raw_x || raw_x->type != CN_CBOR_BYTES || raw_x->length != coord_size) {
87*60b67249SAndroid Build Coastguard Worker     return std::nullopt;
88*60b67249SAndroid Build Coastguard Worker   }
89*60b67249SAndroid Build Coastguard Worker 
90*60b67249SAndroid Build Coastguard Worker   cn_cbor *raw_y = cn_cbor_mapget_int(key, COSE_Key_EC2_Y);
91*60b67249SAndroid Build Coastguard Worker   if (!raw_y || raw_y->type != CN_CBOR_BYTES || raw_y->length != coord_size) {
92*60b67249SAndroid Build Coastguard Worker     return std::nullopt;
93*60b67249SAndroid Build Coastguard Worker   }
94*60b67249SAndroid Build Coastguard Worker 
95*60b67249SAndroid Build Coastguard Worker   bssl::UniquePtr<BIGNUM> x(BN_new());
96*60b67249SAndroid Build Coastguard Worker   bssl::UniquePtr<BIGNUM> y(BN_new());
97*60b67249SAndroid Build Coastguard Worker   bssl::UniquePtr<EC_KEY> eckey(EC_KEY_new_by_curve_name(nid));
98*60b67249SAndroid Build Coastguard Worker   if (!x || !y || !eckey) {
99*60b67249SAndroid Build Coastguard Worker     return std::nullopt;
100*60b67249SAndroid Build Coastguard Worker   }
101*60b67249SAndroid Build Coastguard Worker 
102*60b67249SAndroid Build Coastguard Worker   BN_bin2bn(raw_x->v.bytes, coord_size, x.get());
103*60b67249SAndroid Build Coastguard Worker   BN_bin2bn(raw_y->v.bytes, coord_size, y.get());
104*60b67249SAndroid Build Coastguard Worker   if (0 ==
105*60b67249SAndroid Build Coastguard Worker       EC_KEY_set_public_key_affine_coordinates(eckey.get(), x.get(), y.get())) {
106*60b67249SAndroid Build Coastguard Worker     return std::nullopt;
107*60b67249SAndroid Build Coastguard Worker   }
108*60b67249SAndroid Build Coastguard Worker 
109*60b67249SAndroid Build Coastguard Worker   return eckey;
110*60b67249SAndroid Build Coastguard Worker }
111*60b67249SAndroid Build Coastguard Worker 
112*60b67249SAndroid Build Coastguard Worker }  // namespace
113*60b67249SAndroid Build Coastguard Worker 
114*60b67249SAndroid Build Coastguard Worker // A simple implementation of 'EdDSA_Verify' using boringssl. This function is
115*60b67249SAndroid Build Coastguard Worker // required by 'COSE_Sign1_validate'.
EdDSA_Verify(COSE * cose_signer,int signature_index,COSE_KEY * cose_key,const byte * message,size_t message_size,cose_errback *)116*60b67249SAndroid Build Coastguard Worker bool EdDSA_Verify(COSE *cose_signer, int signature_index, COSE_KEY *cose_key,
117*60b67249SAndroid Build Coastguard Worker                   const byte *message, size_t message_size, cose_errback *) {
118*60b67249SAndroid Build Coastguard Worker   const int64_t kCoseAlgEdDSA = -8;
119*60b67249SAndroid Build Coastguard Worker 
120*60b67249SAndroid Build Coastguard Worker   cn_cbor *signature = _COSE_arrayget_int(cose_signer, signature_index);
121*60b67249SAndroid Build Coastguard Worker   cn_cbor *key = cose_key->m_cborKey;
122*60b67249SAndroid Build Coastguard Worker   if (!signature || !key) {
123*60b67249SAndroid Build Coastguard Worker     return false;
124*60b67249SAndroid Build Coastguard Worker   }
125*60b67249SAndroid Build Coastguard Worker   if (signature->type != CN_CBOR_BYTES || signature->length != 64) {
126*60b67249SAndroid Build Coastguard Worker     return false;
127*60b67249SAndroid Build Coastguard Worker   }
128*60b67249SAndroid Build Coastguard Worker   if (!CheckCoseKeyTypeAndOps(key, COSE_Key_Type_OKP)) {
129*60b67249SAndroid Build Coastguard Worker     return false;
130*60b67249SAndroid Build Coastguard Worker   }
131*60b67249SAndroid Build Coastguard Worker   cn_cbor *curve = cn_cbor_mapget_int(key, COSE_Key_OPK_Curve);
132*60b67249SAndroid Build Coastguard Worker   cn_cbor *x = cn_cbor_mapget_int(key, COSE_Key_OPK_X);
133*60b67249SAndroid Build Coastguard Worker   if (!curve || !x) {
134*60b67249SAndroid Build Coastguard Worker     return false;
135*60b67249SAndroid Build Coastguard Worker   }
136*60b67249SAndroid Build Coastguard Worker   if (curve->type != CN_CBOR_UINT || curve->v.uint != COSE_Curve_Ed25519) {
137*60b67249SAndroid Build Coastguard Worker     return false;
138*60b67249SAndroid Build Coastguard Worker   }
139*60b67249SAndroid Build Coastguard Worker   if (x->type != CN_CBOR_BYTES || x->length != 32) {
140*60b67249SAndroid Build Coastguard Worker     return false;
141*60b67249SAndroid Build Coastguard Worker   }
142*60b67249SAndroid Build Coastguard Worker   if (!CheckCoseKeyAlg(key, kCoseAlgEdDSA)) {
143*60b67249SAndroid Build Coastguard Worker     return false;
144*60b67249SAndroid Build Coastguard Worker   }
145*60b67249SAndroid Build Coastguard Worker   if (1 !=
146*60b67249SAndroid Build Coastguard Worker       ED25519_verify(message, message_size, signature->v.bytes, x->v.bytes)) {
147*60b67249SAndroid Build Coastguard Worker     return false;
148*60b67249SAndroid Build Coastguard Worker   }
149*60b67249SAndroid Build Coastguard Worker   return true;
150*60b67249SAndroid Build Coastguard Worker }
151*60b67249SAndroid Build Coastguard Worker 
152*60b67249SAndroid Build Coastguard Worker // A stub for 'EdDSA_Sign'. This is unused, but helps make linkers happy.
EdDSA_Sign(COSE *,int,COSE_KEY *,const byte *,size_t,cose_errback *)153*60b67249SAndroid Build Coastguard Worker bool EdDSA_Sign(COSE * /*cose_signer*/, int /*signature_index*/,
154*60b67249SAndroid Build Coastguard Worker                 COSE_KEY * /*cose_key*/, const byte * /*message*/,
155*60b67249SAndroid Build Coastguard Worker                 size_t /*message_size*/, cose_errback *) {
156*60b67249SAndroid Build Coastguard Worker   return false;
157*60b67249SAndroid Build Coastguard Worker }
158*60b67249SAndroid Build Coastguard Worker 
159*60b67249SAndroid Build Coastguard Worker // A simple implementation of 'ECDSA_Verify' using boringssl. This function is
160*60b67249SAndroid Build Coastguard Worker // required by 'COSE_Sign1_validate'.
ECDSA_Verify(COSE * cose_signer,int signature_index,COSE_KEY * cose_key,int cbitsDigest,const byte * message,size_t message_size,cose_errback *)161*60b67249SAndroid Build Coastguard Worker bool ECDSA_Verify(COSE *cose_signer, int signature_index, COSE_KEY *cose_key,
162*60b67249SAndroid Build Coastguard Worker                   int cbitsDigest, const byte *message, size_t message_size,
163*60b67249SAndroid Build Coastguard Worker                   cose_errback *) {
164*60b67249SAndroid Build Coastguard Worker   const int64_t kCoseAlgEs256 = -7;
165*60b67249SAndroid Build Coastguard Worker   const int64_t kCoseAlgEs384 = -35;
166*60b67249SAndroid Build Coastguard Worker 
167*60b67249SAndroid Build Coastguard Worker   (void)cbitsDigest;
168*60b67249SAndroid Build Coastguard Worker   cn_cbor *signature = _COSE_arrayget_int(cose_signer, signature_index);
169*60b67249SAndroid Build Coastguard Worker   cn_cbor *key = cose_key->m_cborKey;
170*60b67249SAndroid Build Coastguard Worker   if (!signature || !key) {
171*60b67249SAndroid Build Coastguard Worker     return false;
172*60b67249SAndroid Build Coastguard Worker   }
173*60b67249SAndroid Build Coastguard Worker 
174*60b67249SAndroid Build Coastguard Worker   if (!CheckCoseKeyTypeAndOps(key, COSE_Key_Type_EC2)) {
175*60b67249SAndroid Build Coastguard Worker     return false;
176*60b67249SAndroid Build Coastguard Worker   }
177*60b67249SAndroid Build Coastguard Worker 
178*60b67249SAndroid Build Coastguard Worker   cn_cbor *curve = cn_cbor_mapget_int(key, COSE_Key_OPK_Curve);
179*60b67249SAndroid Build Coastguard Worker   if (!curve || curve->type != CN_CBOR_UINT) {
180*60b67249SAndroid Build Coastguard Worker     return false;
181*60b67249SAndroid Build Coastguard Worker   }
182*60b67249SAndroid Build Coastguard Worker 
183*60b67249SAndroid Build Coastguard Worker   size_t coord_size;
184*60b67249SAndroid Build Coastguard Worker   int nid;
185*60b67249SAndroid Build Coastguard Worker   const EVP_MD *md_type;
186*60b67249SAndroid Build Coastguard Worker   if (curve->v.uint == COSE_Curve_P256) {
187*60b67249SAndroid Build Coastguard Worker     if (!CheckCoseKeyAlg(key, kCoseAlgEs256)) {
188*60b67249SAndroid Build Coastguard Worker       return false;
189*60b67249SAndroid Build Coastguard Worker     }
190*60b67249SAndroid Build Coastguard Worker     coord_size = 32;
191*60b67249SAndroid Build Coastguard Worker     nid = NID_X9_62_prime256v1;
192*60b67249SAndroid Build Coastguard Worker     md_type = EVP_sha256();
193*60b67249SAndroid Build Coastguard Worker   } else if (curve->v.uint == COSE_Curve_P384) {
194*60b67249SAndroid Build Coastguard Worker     if (!CheckCoseKeyAlg(key, kCoseAlgEs384)) {
195*60b67249SAndroid Build Coastguard Worker       return false;
196*60b67249SAndroid Build Coastguard Worker     }
197*60b67249SAndroid Build Coastguard Worker     coord_size = 48;
198*60b67249SAndroid Build Coastguard Worker     nid = NID_secp384r1;
199*60b67249SAndroid Build Coastguard Worker     md_type = EVP_sha384();
200*60b67249SAndroid Build Coastguard Worker   } else {
201*60b67249SAndroid Build Coastguard Worker     return false;
202*60b67249SAndroid Build Coastguard Worker   }
203*60b67249SAndroid Build Coastguard Worker 
204*60b67249SAndroid Build Coastguard Worker   uint8_t md[EVP_MAX_MD_SIZE];
205*60b67249SAndroid Build Coastguard Worker   unsigned int md_size;
206*60b67249SAndroid Build Coastguard Worker   if (1 != EVP_Digest(message, message_size, md, &md_size, md_type, nullptr)) {
207*60b67249SAndroid Build Coastguard Worker     return false;
208*60b67249SAndroid Build Coastguard Worker   }
209*60b67249SAndroid Build Coastguard Worker 
210*60b67249SAndroid Build Coastguard Worker   std::optional<bssl::UniquePtr<EC_KEY>> eckey = GetEcKey(key, nid, coord_size);
211*60b67249SAndroid Build Coastguard Worker   if (!eckey) {
212*60b67249SAndroid Build Coastguard Worker     return false;
213*60b67249SAndroid Build Coastguard Worker   }
214*60b67249SAndroid Build Coastguard Worker 
215*60b67249SAndroid Build Coastguard Worker   if (signature->type != CN_CBOR_BYTES ||
216*60b67249SAndroid Build Coastguard Worker       signature->length != (coord_size * 2)) {
217*60b67249SAndroid Build Coastguard Worker     return false;
218*60b67249SAndroid Build Coastguard Worker   }
219*60b67249SAndroid Build Coastguard Worker 
220*60b67249SAndroid Build Coastguard Worker   bssl::UniquePtr<ECDSA_SIG> sig(ECDSA_SIG_new());
221*60b67249SAndroid Build Coastguard Worker   BN_bin2bn(&signature->v.bytes[0], coord_size, sig->r);
222*60b67249SAndroid Build Coastguard Worker   BN_bin2bn(&signature->v.bytes[coord_size], coord_size, sig->s);
223*60b67249SAndroid Build Coastguard Worker   if (1 != ECDSA_do_verify(md, md_size, sig.get(), eckey->get())) {
224*60b67249SAndroid Build Coastguard Worker     return false;
225*60b67249SAndroid Build Coastguard Worker   }
226*60b67249SAndroid Build Coastguard Worker 
227*60b67249SAndroid Build Coastguard Worker   return true;
228*60b67249SAndroid Build Coastguard Worker }
229*60b67249SAndroid Build Coastguard Worker 
230*60b67249SAndroid Build Coastguard Worker // A stub for 'ECDSA_Sign'. This is unused, but helps make linkers happy.
ECDSA_Sign(COSE *,int,COSE_KEY *,const byte *,size_t,cose_errback *)231*60b67249SAndroid Build Coastguard Worker bool ECDSA_Sign(COSE * /*cose_signer*/, int /*signature_index*/,
232*60b67249SAndroid Build Coastguard Worker                 COSE_KEY * /*cose_key*/, const byte * /*message*/,
233*60b67249SAndroid Build Coastguard Worker                 size_t /*message_size*/, cose_errback *) {
234*60b67249SAndroid Build Coastguard Worker   return false;
235*60b67249SAndroid Build Coastguard Worker }
236