| // Copyright 2020 Google LLC | 
 | // | 
 | // Licensed under the Apache License, Version 2.0 (the "License"); you may not | 
 | // use this file except in compliance with the License. You may obtain a copy of | 
 | // the License at | 
 | // | 
 | //     https://www.apache.org/licenses/LICENSE-2.0 | 
 | // | 
 | // Unless required by applicable law or agreed to in writing, software | 
 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | 
 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | 
 | // License for the specific language governing permissions and limitations under | 
 | // the License. | 
 |  | 
 | // If no variable length descriptors are used in a DICE certificate, the | 
 | // certificate can be constructed from a template instead of using a CBOR | 
 | // library. This implementation includes only hashes and inline configuration in | 
 | // the DICE extension. For convenience this uses only the lower level curve25519 | 
 | // implementation in boringssl. This approach may be especially useful in very | 
 | // low level components where simplicity is paramount. | 
 |  | 
 | // This is an implementation of the DiceGenerateCertificate that generates a | 
 | // CWT-style CBOR certificate based on a template using the ED25519-SHA512 | 
 | // signature scheme. | 
 | // | 
 | // If no variable length descriptors are used in a DICE certificate, the | 
 | // certificate can be constructed from a template instead of using a CBOR / | 
 | // COSE library. This implementation includes only hashes and inline | 
 | // configuration in the certificate fields. This approach may be especially | 
 | // useful in very low level components where simplicity is paramount. | 
 | // | 
 | // This function will return kDiceResultInvalidInput if 'input_values' specifies | 
 | // any variable length descriptors. In particular: | 
 | //   * code_descriptor_size must be zero | 
 | //   * authority_descriptor_size must be zero | 
 | //   * config_type must be kDiceConfigTypeInline | 
 |  | 
 | #include <stdint.h> | 
 | #include <string.h> | 
 |  | 
 | #include "dice/dice.h" | 
 | #include "dice/ops.h" | 
 | #include "dice/profile_name.h" | 
 | #include "dice/utils.h" | 
 |  | 
 | #if DICE_PUBLIC_KEY_BUFFER_SIZE != 32 | 
 | #error "Only Ed25519 is supported; 32 bytes needed to store the public key." | 
 | #endif | 
 | #if DICE_SIGNATURE_BUFFER_SIZE != 64 | 
 | #error "Only Ed25519 is supported; 64 bytes needed to store the signature." | 
 | #endif | 
 |  | 
 | // 20 bytes of header, 366 bytes of payload. | 
 | #define DICE_TBS_SIZE 386 | 
 |  | 
 | // A well-formed certificate, but with zeros in all fields to be filled. | 
 | static const uint8_t kTemplate[441] = { | 
 |     // Constant encoding. | 
 |     0x84, 0x43, 0xa1, 0x01, 0x27, 0xa0, 0x59, 0x01, 0x6e, | 
 |     // Offset 9: Payload starts here, 366 bytes. | 
 |     0xa8, 0x01, 0x78, 0x28, | 
 |     // Offset 13: CWT issuer, 40 bytes. | 
 |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 
 |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 
 |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 
 |     0x00, 0x00, 0x00, 0x00, | 
 |     // Constant encoding. | 
 |     0x02, 0x78, 0x28, | 
 |     // Offset 56: CWT subject, 40 bytes. | 
 |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 
 |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 
 |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 
 |     0x00, 0x00, 0x00, 0x00, | 
 |     // Constant encoding. | 
 |     0x3a, 0x00, 0x47, 0x44, 0x50, 0x58, 0x40, | 
 |     // Offset 103: Code hash, 64 bytes. | 
 |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 
 |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 
 |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 
 |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 
 |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 
 |     0x00, 0x00, 0x00, 0x00, | 
 |     // Constant encoding. | 
 |     0x3a, 0x00, 0x47, 0x44, 0x53, 0x58, 0x40, | 
 |     // Offset 174: Configuration value, 64 bytes. | 
 |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 
 |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 
 |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 
 |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 
 |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 
 |     0x00, 0x00, 0x00, 0x00, | 
 |     // Constant encoding. | 
 |     0x3a, 0x00, 0x47, 0x44, 0x54, 0x58, 0x40, | 
 |     // Offset 245: Authority hash, 64 bytes. | 
 |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 
 |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 
 |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 
 |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 
 |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 
 |     0x00, 0x00, 0x00, 0x00, | 
 |     // Constant encoding. | 
 |     0x3a, 0x00, 0x47, 0x44, 0x56, 0x41, | 
 |     // Offset 315: Mode, 1 byte. | 
 |     0x00, | 
 |     // Constant encoding. | 
 |     0x3a, 0x00, 0x47, 0x44, 0x57, 0x58, 0x2d, 0xa5, 0x01, 0x01, 0x03, 0x27, | 
 |     0x04, 0x81, 0x02, 0x20, 0x06, 0x21, 0x58, 0x20, | 
 |     // Offset 336: Public key, 32 bytes. | 
 |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 
 |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 
 |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 
 |     // Constant encoding (key usage). | 
 |     0x3a, 0x00, 0x47, 0x44, 0x58, 0x41, 0x20, | 
 |     // Offset 375: Payload ends here. | 
 |     // Constant encoding. | 
 |     0x58, 0x40, | 
 |     // Offset 377: Signature, 64 bytes. | 
 |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 
 |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 
 |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 
 |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 
 |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 
 |     0x00, 0x00, 0x00, 0x00}; | 
 |  | 
 | // The data to be signed is not the certificate, but the payload appended to | 
 | // this header. This is the 'Sig_structure' for COSE_Sign1, per RFC 8152. | 
 | static const uint8_t kTbsHeader[20] = {0x84, 0x6a, 0x53, 0x69, 0x67, 0x6e, 0x61, | 
 |                                        0x74, 0x75, 0x72, 0x65, 0x31, 0x43, 0xa1, | 
 |                                        0x01, 0x27, 0x40, 0x59, 0x01, 0x6e}; | 
 |  | 
 | static const struct { | 
 |   size_t offset; | 
 |   size_t length; | 
 | } kFieldTable[] = {{13, 40},   // Issuer | 
 |                    {56, 40},   // Subject | 
 |                    {103, 64},  // Code hash | 
 |                    {174, 64},  // Config descriptor | 
 |                    {245, 64},  // Authority hash | 
 |                    {315, 1},   // Mode | 
 |                    {336, 32},  // Public key | 
 |                    {377, 64},  // Signature | 
 |                    {9, 366}};  // Payload | 
 |  | 
 | static const size_t kFieldIndexIssuer = 0; | 
 | static const size_t kFieldIndexSubject = 1; | 
 | static const size_t kFieldIndexCodeHash = 2; | 
 | static const size_t kFieldIndexConfigDescriptor = 3; | 
 | static const size_t kFieldIndexAuthorityHash = 4; | 
 | static const size_t kFieldIndexMode = 5; | 
 | static const size_t kFieldIndexSubjectPublicKey = 6; | 
 | static const size_t kFieldIndexSignature = 7; | 
 | static const size_t kFieldIndexPayload = 8; | 
 |  | 
 | // |buffer| must point to the beginning of the template buffer and |src| must | 
 | // point to at least <field-length> bytes. | 
 | static void CopyField(const uint8_t* src, size_t index, uint8_t* buffer) { | 
 |   memcpy(&buffer[kFieldTable[index].offset], src, kFieldTable[index].length); | 
 | } | 
 |  | 
 | DiceResult DiceGenerateCertificate( | 
 |     void* context, | 
 |     const uint8_t subject_private_key_seed[DICE_PRIVATE_KEY_SEED_SIZE], | 
 |     const uint8_t authority_private_key_seed[DICE_PRIVATE_KEY_SEED_SIZE], | 
 |     const DiceInputValues* input_values, size_t certificate_buffer_size, | 
 |     uint8_t* certificate, size_t* certificate_actual_size) { | 
 |   DiceResult result = kDiceResultOk; | 
 |  | 
 |   DiceKeyParam key_param; | 
 |   result = DiceGetKeyParam(context, kDicePrincipalSubject, &key_param); | 
 |   if (result != kDiceResultOk) { | 
 |     goto out; | 
 |   } | 
 |  | 
 |   // Variable length descriptors are not supported. | 
 |   if (input_values->code_descriptor_size > 0 || | 
 |       input_values->config_type != kDiceConfigTypeInline || | 
 |       input_values->authority_descriptor_size > 0 || DICE_PROFILE_NAME) { | 
 |     return kDiceResultInvalidInput; | 
 |   } | 
 |  | 
 |   // We know the certificate size upfront so we can do the buffer size check. | 
 |   *certificate_actual_size = sizeof(kTemplate); | 
 |   if (certificate_buffer_size < sizeof(kTemplate)) { | 
 |     return kDiceResultBufferTooSmall; | 
 |   } | 
 |  | 
 |   // Declare buffers which are cleared on 'goto out'. | 
 |   uint8_t subject_private_key[DICE_PRIVATE_KEY_BUFFER_SIZE]; | 
 |   uint8_t authority_private_key[DICE_PRIVATE_KEY_BUFFER_SIZE]; | 
 |  | 
 |   // Derive keys and IDs from the private key seeds. | 
 |   uint8_t subject_public_key[DICE_PUBLIC_KEY_BUFFER_SIZE]; | 
 |   result = DiceKeypairFromSeed(context, kDicePrincipalSubject, | 
 |                                subject_private_key_seed, subject_public_key, | 
 |                                subject_private_key); | 
 |   if (result != kDiceResultOk) { | 
 |     goto out; | 
 |   } | 
 |  | 
 |   uint8_t subject_id[DICE_ID_SIZE]; | 
 |   result = DiceDeriveCdiCertificateId(context, subject_public_key, | 
 |                                       DICE_PUBLIC_KEY_BUFFER_SIZE, subject_id); | 
 |   if (result != kDiceResultOk) { | 
 |     goto out; | 
 |   } | 
 |   uint8_t subject_id_hex[40]; | 
 |   DiceHexEncode(subject_id, sizeof(subject_id), subject_id_hex, | 
 |                 sizeof(subject_id_hex)); | 
 |  | 
 |   uint8_t authority_public_key[DICE_PUBLIC_KEY_BUFFER_SIZE]; | 
 |   result = DiceKeypairFromSeed(context, kDicePrincipalAuthority, | 
 |                                authority_private_key_seed, authority_public_key, | 
 |                                authority_private_key); | 
 |   if (result != kDiceResultOk) { | 
 |     goto out; | 
 |   } | 
 |  | 
 |   uint8_t authority_id[DICE_ID_SIZE]; | 
 |   result = DiceDeriveCdiCertificateId( | 
 |       context, authority_public_key, DICE_PUBLIC_KEY_BUFFER_SIZE, authority_id); | 
 |   if (result != kDiceResultOk) { | 
 |     goto out; | 
 |   } | 
 |   uint8_t authority_id_hex[40]; | 
 |   DiceHexEncode(authority_id, sizeof(authority_id), authority_id_hex, | 
 |                 sizeof(authority_id_hex)); | 
 |  | 
 |   // First copy in the entire template, then fill in the fields. | 
 |   memcpy(certificate, kTemplate, sizeof(kTemplate)); | 
 |   CopyField(authority_id_hex, kFieldIndexIssuer, certificate); | 
 |   CopyField(subject_id_hex, kFieldIndexSubject, certificate); | 
 |   CopyField(subject_public_key, kFieldIndexSubjectPublicKey, certificate); | 
 |   CopyField(input_values->code_hash, kFieldIndexCodeHash, certificate); | 
 |   CopyField(input_values->config_value, kFieldIndexConfigDescriptor, | 
 |             certificate); | 
 |   CopyField(input_values->authority_hash, kFieldIndexAuthorityHash, | 
 |             certificate); | 
 |   certificate[kFieldTable[kFieldIndexMode].offset] = input_values->mode; | 
 |  | 
 |   // Fill the TBS structure using the payload from the certificate. | 
 |   uint8_t tbs[DICE_TBS_SIZE]; | 
 |   memcpy(tbs, kTbsHeader, sizeof(kTbsHeader)); | 
 |   memcpy(&tbs[sizeof(kTbsHeader)], | 
 |          &certificate[kFieldTable[kFieldIndexPayload].offset], | 
 |          kFieldTable[kFieldIndexPayload].length); | 
 |  | 
 |   uint8_t signature[DICE_SIGNATURE_BUFFER_SIZE]; | 
 |   result = | 
 |       DiceSign(context, tbs, sizeof(tbs), authority_private_key, signature); | 
 |   if (result != kDiceResultOk) { | 
 |     goto out; | 
 |   } | 
 |   result = | 
 |       DiceVerify(context, tbs, sizeof(tbs), signature, authority_public_key); | 
 |   if (result != kDiceResultOk) { | 
 |     goto out; | 
 |   } | 
 |   CopyField(signature, kFieldIndexSignature, certificate); | 
 |  | 
 | out: | 
 |   DiceClearMemory(context, sizeof(subject_private_key), subject_private_key); | 
 |   DiceClearMemory(context, sizeof(authority_private_key), | 
 |                   authority_private_key); | 
 |   return result; | 
 | } |