• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 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/curve25519.h"
22 #include "openssl/is_boringssl.h"
23 
24 // Gets the public key from a well-formed Ed25519 COSE_Key. On success populates
25 // |public_key| and returns true.
GetPublicKeyFromCbor(const cn_cbor * key,uint8_t public_key[PUBLIC_KEY_SIZE])26 static bool GetPublicKeyFromCbor(const cn_cbor *key,
27                                  uint8_t public_key[PUBLIC_KEY_SIZE]) {
28   const int64_t kCoseKeyAlgLabel = 3;
29   const int64_t kCoseKeyOpsLabel = 4;
30   const uint64_t kCoseKeyOpsVerify = 2;
31   const int64_t kCoseAlgEdDSA = -8;
32 
33   // Mandatory attributes.
34   cn_cbor *type = cn_cbor_mapget_int(key, COSE_Key_Type);
35   cn_cbor *curve = cn_cbor_mapget_int(key, COSE_Key_OPK_Curve);
36   cn_cbor *x = cn_cbor_mapget_int(key, COSE_Key_OPK_X);
37   if (!type || !curve || !x) {
38     return false;
39   }
40   if (type->type != CN_CBOR_UINT || type->v.uint != COSE_Key_Type_OKP) {
41     return false;
42   }
43   if (curve->type != CN_CBOR_UINT || curve->v.uint != COSE_Curve_Ed25519) {
44     return false;
45   }
46   if (x->type != CN_CBOR_BYTES || x->length != PUBLIC_KEY_SIZE) {
47     return false;
48   }
49   // Optional attributes.
50   cn_cbor *alg = cn_cbor_mapget_int(key, kCoseKeyAlgLabel);
51   if (alg) {
52     if (alg->type != CN_CBOR_INT || alg->v.sint != kCoseAlgEdDSA) {
53       return false;
54     }
55   }
56   cn_cbor *ops = cn_cbor_mapget_int(key, kCoseKeyOpsLabel);
57   if (ops) {
58     if (ops->type != CN_CBOR_ARRAY || ops->length == 0) {
59       return false;
60     }
61     bool found_verify = false;
62     for (size_t i = 0; i < ops->length; ++i) {
63       cn_cbor *item = cn_cbor_index(ops, i);
64       if (!item || item->type != CN_CBOR_UINT) {
65         return false;
66       }
67       if (item->v.uint == kCoseKeyOpsVerify) {
68         found_verify = true;
69       }
70     }
71     if (!found_verify) {
72       return false;
73     }
74   }
75 
76   memcpy(public_key, x->v.bytes, PUBLIC_KEY_SIZE);
77   return true;
78 }
79 
80 // A simple implementation of 'EdDSA_Verify' using boringssl. This function is
81 // 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 *)82 bool EdDSA_Verify(COSE *cose_signer, int signature_index, COSE_KEY *cose_key,
83                   const byte *message, size_t message_size, cose_errback *) {
84   cn_cbor *signature = _COSE_arrayget_int(cose_signer, signature_index);
85   cn_cbor *key = cose_key->m_cborKey;
86   if (!signature || !key) {
87     return false;
88   }
89   if (signature->type != CN_CBOR_BYTES || signature->length != 64) {
90     return false;
91   }
92   uint8_t public_key[PUBLIC_KEY_SIZE];
93   if (!GetPublicKeyFromCbor(key, public_key)) {
94     return false;
95   }
96   return (1 == ED25519_verify(message, message_size, signature->v.bytes,
97                               public_key));
98 }
99 
100 // 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 *)101 bool EdDSA_Sign(COSE * /*cose_signer*/, int /*signature_index*/,
102                 COSE_KEY * /*cose_key*/, const byte * /*message*/,
103                 size_t /*message_size*/, cose_errback *) {
104   return false;
105 }
106