|  | // 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. | 
|  |  | 
|  | // This is an implementation of the DiceGenerateCertificate that generates an | 
|  | // X.509 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 an ASN.1 | 
|  | // library. This implementation includes only hashes and inline configuration in | 
|  | // the DICE extension. For convenience this uses the lower level curve25519 | 
|  | // implementation in boringssl but does not use anything else (no ASN.1, X.509, | 
|  | // etc). 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" | 
|  | #include "openssl/curve25519.h" | 
|  | #include "openssl/is_boringssl.h" | 
|  |  | 
|  | // A well-formed certificate, but with zeros in all fields to be filled. | 
|  | static const uint8_t kTemplate[638] = { | 
|  | // Constant encoding. | 
|  | 0x30, 0x82, 0x02, 0x7a, | 
|  | // Offset 4: TBS starts here. | 
|  | // Constant encoding. | 
|  | 0x30, 0x82, 0x02, 0x2c, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x14, | 
|  | // Offset 15: Serial number, 20 bytes. | 
|  | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 
|  | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 
|  | // Constant encoding. | 
|  | 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x30, 0x33, 0x31, 0x31, 0x30, | 
|  | 0x2f, 0x06, 0x03, 0x55, 0x04, 0x05, 0x13, 0x28, | 
|  | // Offset 55: Issuer name, 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. | 
|  | 0x30, 0x20, 0x17, 0x0d, 0x31, 0x38, 0x30, 0x33, 0x32, 0x32, 0x32, 0x33, | 
|  | 0x35, 0x39, 0x35, 0x39, 0x5a, 0x18, 0x0f, 0x39, 0x39, 0x39, 0x39, 0x31, | 
|  | 0x32, 0x33, 0x31, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x33, | 
|  | 0x31, 0x31, 0x30, 0x2f, 0x06, 0x03, 0x55, 0x04, 0x05, 0x13, 0x28, | 
|  | // Offset 142: Subject name, 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. | 
|  | 0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x03, 0x21, 0x00, | 
|  | // Offset 194: Subject 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. | 
|  | 0xa3, 0x82, 0x01, 0x4e, 0x30, 0x82, 0x01, 0x4a, 0x30, 0x1f, 0x06, 0x03, | 
|  | 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, | 
|  | // Offset 247: Authority key identifier, 20 bytes. | 
|  | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 
|  | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 
|  | // Constant encoding. | 
|  | 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, | 
|  | // Offset 278: Subject key identifier, 20 bytes. | 
|  | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 
|  | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 
|  | // Constant encoding. | 
|  | 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, | 
|  | 0x03, 0x02, 0x02, 0x04, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, | 
|  | 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x81, 0xe6, | 
|  | 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6, 0x79, 0x02, 0x01, 0x18, | 
|  | 0x01, 0x01, 0xff, 0x04, 0x81, 0xd4, 0x30, 0x81, 0xd1, 0xa0, 0x42, 0x04, | 
|  | 0x40, | 
|  | // Offset 356: 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. | 
|  | 0xa3, 0x42, 0x04, 0x40, | 
|  | // Offset 424: 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. | 
|  | 0xa4, 0x42, 0x04, 0x40, | 
|  | // Offset 492: 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. | 
|  | 0xa6, 0x03, 0x0a, 0x01, | 
|  | // Offset 560: Mode, 1 byte. | 
|  | 0x00, | 
|  | // Offset 561: TBS ends here. | 
|  | // Constant encoding. | 
|  | 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x03, 0x41, 0x00, | 
|  | // Offset 571: 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}; | 
|  |  | 
|  | static const struct { | 
|  | size_t offset; | 
|  | size_t length; | 
|  | } kFieldTable[] = {{15, 20},   // Serial number | 
|  | {55, 40},   // Issuer name | 
|  | {142, 40},  // Subject name | 
|  | {194, 32},  // Subject public key | 
|  | {247, 20},  // Authority key id | 
|  | {278, 20},  // Subject key id | 
|  | {359, 64},  // Code hash | 
|  | {427, 64},  // Config descriptor | 
|  | {495, 64},  // Authority hash | 
|  | {563, 1},   // Mode | 
|  | {574, 64},  // Signature | 
|  | {4, 560}};  // Entire TBS | 
|  |  | 
|  | static const size_t kFieldIndexSerial = 0; | 
|  | static const size_t kFieldIndexIssuerName = 1; | 
|  | static const size_t kFieldIndexSubjectName = 2; | 
|  | static const size_t kFieldIndexSubjectPublicKey = 3; | 
|  | static const size_t kFieldIndexAuthorityKeyId = 4; | 
|  | static const size_t kFieldIndexSubjectKeyId = 5; | 
|  | static const size_t kFieldIndexCodeHash = 6; | 
|  | static const size_t kFieldIndexConfigDescriptor = 7; | 
|  | static const size_t kFieldIndexAuthorityHash = 8; | 
|  | static const size_t kFieldIndexMode = 9; | 
|  | static const size_t kFieldIndexSignature = 10; | 
|  | static const size_t kFieldIndexTbs = 11; | 
|  |  | 
|  | // |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_bssl_private_key[64]; | 
|  | uint8_t authority_bssl_private_key[64]; | 
|  |  | 
|  | // Derive keys and IDs from the private key seeds. | 
|  | uint8_t subject_public_key[32]; | 
|  | ED25519_keypair_from_seed(subject_public_key, subject_bssl_private_key, | 
|  | subject_private_key_seed); | 
|  |  | 
|  | uint8_t subject_id[DICE_ID_SIZE]; | 
|  | result = | 
|  | DiceDeriveCdiCertificateId(context, subject_public_key, 32, 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[32]; | 
|  | ED25519_keypair_from_seed(authority_public_key, authority_bssl_private_key, | 
|  | authority_private_key_seed); | 
|  |  | 
|  | uint8_t authority_id[DICE_ID_SIZE]; | 
|  | result = DiceDeriveCdiCertificateId(context, authority_public_key, 32, | 
|  | 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(subject_id, kFieldIndexSerial, certificate); | 
|  | CopyField(authority_id_hex, kFieldIndexIssuerName, certificate); | 
|  | CopyField(subject_id_hex, kFieldIndexSubjectName, certificate); | 
|  | CopyField(subject_public_key, kFieldIndexSubjectPublicKey, certificate); | 
|  | CopyField(authority_id, kFieldIndexAuthorityKeyId, certificate); | 
|  | CopyField(subject_id, kFieldIndexSubjectKeyId, 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; | 
|  |  | 
|  | // All the TBS fields are filled in, we're ready to sign. | 
|  | uint8_t signature[64]; | 
|  | if (1 != ED25519_sign(signature, | 
|  | &certificate[kFieldTable[kFieldIndexTbs].offset], | 
|  | kFieldTable[kFieldIndexTbs].length, | 
|  | authority_bssl_private_key)) { | 
|  | result = kDiceResultPlatformError; | 
|  | goto out; | 
|  | } | 
|  | if (1 != ED25519_verify(&certificate[kFieldTable[kFieldIndexTbs].offset], | 
|  | kFieldTable[kFieldIndexTbs].length, signature, | 
|  | authority_public_key)) { | 
|  | result = kDiceResultPlatformError; | 
|  | goto out; | 
|  | } | 
|  | CopyField(signature, kFieldIndexSignature, certificate); | 
|  |  | 
|  | out: | 
|  | DiceClearMemory(context, sizeof(subject_bssl_private_key), | 
|  | subject_bssl_private_key); | 
|  | DiceClearMemory(context, sizeof(authority_bssl_private_key), | 
|  | authority_bssl_private_key); | 
|  | return result; | 
|  | } |