• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2023 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 #include <stdint.h>
16 #include <string.h>
17 
18 #include "cose/cose.h"
19 #include "cose/cose_configure.h"
20 #include "cose_int.h"
21 #include "openssl/bn.h"
22 #include "openssl/ec.h"
23 #include "openssl/ec_key.h"
24 #include "openssl/ecdsa.h"
25 #include "openssl/evp.h"
26 #include "openssl/hkdf.h"
27 #include "openssl/is_boringssl.h"
28 #include "openssl/sha.h"
29 
30 // Gets the public key from a well-formed ECDSA P-384 COSE_Key. On
31 // success populates |public_key| and returns true; public_key must hold 96
32 // bytes (uncompressed format).
GetPublicKeyFromCbor(const cn_cbor * key,uint8_t * public_key)33 static bool GetPublicKeyFromCbor(const cn_cbor *key, uint8_t *public_key) {
34   const int64_t kCoseKeyAlgLabel = 3;
35   const int64_t kCoseKeyOpsLabel = 4;
36   const uint64_t kCoseKeyOpsVerify = 2;
37   const int64_t kCoseAlgEs384 = -35;
38 
39   // Mandatory attributes.
40   cn_cbor *type = cn_cbor_mapget_int(key, COSE_Key_Type);
41   cn_cbor *curve = cn_cbor_mapget_int(key, COSE_Key_OPK_Curve);
42   if (!type || !curve) {
43     return false;
44   }
45   if (type->type != CN_CBOR_UINT || curve->type != CN_CBOR_UINT) {
46     return false;
47   }
48 
49   if (type->v.uint != COSE_Key_Type_EC2 || curve->v.uint != COSE_Curve_P384) {
50     return false;
51   }
52 
53   cn_cbor *x = cn_cbor_mapget_int(key, COSE_Key_EC2_X);
54   if (!x || x->type != CN_CBOR_BYTES || x->length != (PUBLIC_KEY_SIZE / 2)) {
55     return false;
56   }
57 
58   cn_cbor *y = cn_cbor_mapget_int(key, COSE_Key_EC2_Y);
59   if (!y || y->type != CN_CBOR_BYTES || y->length != (PUBLIC_KEY_SIZE / 2)) {
60     return false;
61   }
62 
63   cn_cbor *alg = cn_cbor_mapget_int(key, kCoseKeyAlgLabel);
64   if (alg) {
65     if (alg->type != CN_CBOR_INT || alg->v.sint != kCoseAlgEs384) {
66       return false;
67     }
68   }
69 
70   cn_cbor *ops = cn_cbor_mapget_int(key, kCoseKeyOpsLabel);
71   if (ops) {
72     if (ops->type != CN_CBOR_ARRAY || ops->length == 0) {
73       return false;
74     }
75     bool found_verify = false;
76     for (size_t i = 0; i < ops->length; ++i) {
77       cn_cbor *item = cn_cbor_index(ops, i);
78       if (!item || item->type != CN_CBOR_UINT) {
79         return false;
80       }
81       if (item->v.uint == kCoseKeyOpsVerify) {
82         found_verify = true;
83       }
84     }
85     if (!found_verify) {
86       return false;
87     }
88   }
89 
90   memcpy(&public_key[0], x->v.bytes, PUBLIC_KEY_SIZE / 2);
91   memcpy(&public_key[PUBLIC_KEY_SIZE / 2], y->v.bytes, PUBLIC_KEY_SIZE / 2);
92   return true;
93 }
94 
ECDSA_Verify(COSE * cose_signer,int signature_index,COSE_KEY * cose_key,int cbitsDigest,const byte * message,size_t message_size,cose_errback *)95 bool ECDSA_Verify(COSE *cose_signer, int signature_index, COSE_KEY *cose_key,
96                   int cbitsDigest, const byte *message, size_t message_size,
97                   cose_errback *) {
98   (void)cbitsDigest;
99   cn_cbor *signature = _COSE_arrayget_int(cose_signer, signature_index);
100   cn_cbor *key = cose_key->m_cborKey;
101   if (!signature || !key) {
102     return false;
103   }
104   if (signature->type != CN_CBOR_BYTES ||
105       signature->length != PUBLIC_KEY_SIZE) {
106     return false;
107   }
108   uint8_t public_key[PUBLIC_KEY_SIZE];
109   if (!GetPublicKeyFromCbor(key, public_key)) {
110     return false;
111   }
112 
113   // Implementation of ECDSA verification starts here
114   uint8_t output[48];
115   SHA384(message, message_size, output);
116   EC_KEY *eckey = EC_KEY_new_by_curve_name(NID_secp384r1);
117   BIGNUM *x = BN_new();
118   BN_bin2bn(&public_key[0], 48, x);
119   BIGNUM *y = BN_new();
120   BN_bin2bn(&public_key[48], 48, y);
121   int result = EC_KEY_set_public_key_affine_coordinates(eckey, x, y);
122 
123   BN_clear_free(y);
124   BN_clear_free(x);
125 
126   if (result == 0) {
127     printf("Setting affine coordinates failed\n");
128     return false;
129   }
130 
131   ECDSA_SIG *sig = ECDSA_SIG_new();
132   BN_bin2bn(&(signature->v.bytes[0]), 48, sig->r);
133   BN_bin2bn(&(signature->v.bytes[48]), 48, sig->s);
134   result = ECDSA_do_verify(output, 48, sig, eckey);
135 
136   EC_KEY_free(eckey);
137   ECDSA_SIG_free(sig);
138   if (1 != result) {
139     return false;
140   }
141   return true;
142 }
143 
144 // 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 *)145 bool ECDSA_Sign(COSE * /*cose_signer*/, int /*signature_index*/,
146                 COSE_KEY * /*cose_key*/, const byte * /*message*/,
147                 size_t /*message_size*/, cose_errback *) {
148   return false;
149 }
150