Randall Spangler | c644a8c | 2014-11-21 11:04:36 -0800 | [diff] [blame] | 1 | /* Copyright (c) 2014 The Chromium OS Authors. All rights reserved. |
| 2 | * Use of this source code is governed by a BSD-style license that can be |
| 3 | * found in the LICENSE file. |
| 4 | * |
| 5 | * Host functions for signatures. |
| 6 | */ |
| 7 | |
| 8 | #define OPENSSL_NO_SHA |
Randall Spangler | c644a8c | 2014-11-21 11:04:36 -0800 | [diff] [blame] | 9 | #include <openssl/rsa.h> |
| 10 | |
| 11 | #include "2sysincludes.h" |
| 12 | #include "2common.h" |
| 13 | #include "2rsa.h" |
| 14 | #include "2sha.h" |
Randall Spangler | 108d991 | 2014-12-02 15:55:56 -0800 | [diff] [blame] | 15 | #include "vb2_common.h" |
Randall Spangler | c644a8c | 2014-11-21 11:04:36 -0800 | [diff] [blame] | 16 | #include "host_common.h" |
| 17 | #include "host_key2.h" |
| 18 | #include "host_signature2.h" |
| 19 | #include "host_misc.h" |
| 20 | |
| 21 | /** |
| 22 | * Get the digest info for a hash algorithm |
| 23 | * |
| 24 | * @param hash_alg Hash algorithm |
| 25 | * @param buf_ptr On success, points to the digest info |
| 26 | * @param size_ptr On success, contains the info size in bytes |
| 27 | * @return VB2_SUCCESS, or non-zero error code on failure. |
| 28 | */ |
| 29 | static int vb2_digest_info(enum vb2_hash_algorithm hash_alg, |
| 30 | const uint8_t **buf_ptr, |
| 31 | uint32_t *size_ptr) |
| 32 | { |
| 33 | *buf_ptr = NULL; |
| 34 | *size_ptr = 0; |
| 35 | |
| 36 | switch (hash_alg) { |
| 37 | #if VB2_SUPPORT_SHA1 |
| 38 | case VB2_HASH_SHA1: |
| 39 | { |
| 40 | static const uint8_t info[] = { |
| 41 | 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, |
| 42 | 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14 |
| 43 | }; |
| 44 | *buf_ptr = info; |
| 45 | *size_ptr = sizeof(info); |
| 46 | return VB2_SUCCESS; |
| 47 | } |
| 48 | #endif |
| 49 | #if VB2_SUPPORT_SHA256 |
| 50 | case VB2_HASH_SHA256: |
| 51 | { |
| 52 | static const uint8_t info[] = { |
| 53 | 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, |
| 54 | 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, |
| 55 | 0x00, 0x04, 0x20 |
| 56 | }; |
| 57 | *buf_ptr = info; |
| 58 | *size_ptr = sizeof(info); |
| 59 | return VB2_SUCCESS; |
| 60 | } |
| 61 | #endif |
| 62 | #if VB2_SUPPORT_SHA512 |
| 63 | case VB2_HASH_SHA512: |
| 64 | { |
| 65 | static const uint8_t info[] = { |
| 66 | 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, |
| 67 | 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, |
| 68 | 0x00, 0x04, 0x40 |
| 69 | }; |
| 70 | *buf_ptr = info; |
| 71 | *size_ptr = sizeof(info); |
| 72 | return VB2_SUCCESS; |
| 73 | } |
| 74 | #endif |
| 75 | default: |
| 76 | return VB2_ERROR_DIGEST_INFO; |
| 77 | } |
| 78 | } |
| 79 | |
Randall Spangler | 308d254 | 2014-12-04 09:54:37 -0800 | [diff] [blame] | 80 | int vb2_sign_data(struct vb2_signature **sig_ptr, |
Randall Spangler | c644a8c | 2014-11-21 11:04:36 -0800 | [diff] [blame] | 81 | const uint8_t *data, |
| 82 | uint32_t size, |
| 83 | const struct vb2_private_key *key, |
| 84 | const char *desc) |
| 85 | { |
Randall Spangler | 308d254 | 2014-12-04 09:54:37 -0800 | [diff] [blame] | 86 | struct vb2_signature s = { |
| 87 | .c.magic = VB2_MAGIC_SIGNATURE, |
| 88 | .c.struct_version_major = VB2_SIGNATURE_VERSION_MAJOR, |
| 89 | .c.struct_version_minor = VB2_SIGNATURE_VERSION_MINOR, |
Randall Spangler | c644a8c | 2014-11-21 11:04:36 -0800 | [diff] [blame] | 90 | .c.fixed_size = sizeof(s), |
| 91 | .sig_alg = key->sig_alg, |
| 92 | .hash_alg = key->hash_alg, |
| 93 | .data_size = size, |
Bill Richardson | 36bc591 | 2015-03-04 16:13:45 -0800 | [diff] [blame] | 94 | .id = key->id, |
Randall Spangler | c644a8c | 2014-11-21 11:04:36 -0800 | [diff] [blame] | 95 | }; |
| 96 | |
| 97 | struct vb2_digest_context dc; |
| 98 | uint32_t digest_size; |
| 99 | const uint8_t *info = NULL; |
| 100 | uint32_t info_size = 0; |
| 101 | uint32_t sig_digest_size; |
| 102 | uint8_t *sig_digest; |
| 103 | uint8_t *buf; |
| 104 | |
| 105 | *sig_ptr = NULL; |
| 106 | |
| 107 | /* Use key description if no description supplied */ |
| 108 | if (!desc) |
| 109 | desc = key->desc; |
| 110 | |
| 111 | s.c.desc_size = vb2_desc_size(desc); |
| 112 | |
| 113 | s.sig_offset = s.c.fixed_size + s.c.desc_size; |
| 114 | s.sig_size = vb2_sig_size(key->sig_alg, key->hash_alg); |
| 115 | if (!s.sig_size) |
| 116 | return VB2_SIGN_DATA_SIG_SIZE; |
| 117 | |
| 118 | s.c.total_size = s.sig_offset + s.sig_size; |
| 119 | |
| 120 | /* Determine digest size and allocate buffer */ |
| 121 | if (s.sig_alg != VB2_SIG_NONE) { |
| 122 | if (vb2_digest_info(s.hash_alg, &info, &info_size)) |
| 123 | return VB2_SIGN_DATA_DIGEST_INFO; |
| 124 | } |
| 125 | |
| 126 | digest_size = vb2_digest_size(key->hash_alg); |
| 127 | if (!digest_size) |
| 128 | return VB2_SIGN_DATA_DIGEST_SIZE; |
| 129 | |
| 130 | sig_digest_size = info_size + digest_size; |
| 131 | sig_digest = malloc(sig_digest_size); |
| 132 | if (!sig_digest) |
| 133 | return VB2_SIGN_DATA_DIGEST_ALLOC; |
| 134 | |
| 135 | /* Prepend digest info, if any */ |
| 136 | if (info_size) |
| 137 | memcpy(sig_digest, info, info_size); |
| 138 | |
| 139 | /* Calculate hash digest */ |
| 140 | if (vb2_digest_init(&dc, s.hash_alg)) { |
| 141 | free(sig_digest); |
| 142 | return VB2_SIGN_DATA_DIGEST_INIT; |
| 143 | } |
| 144 | |
| 145 | if (vb2_digest_extend(&dc, data, size)) { |
| 146 | free(sig_digest); |
| 147 | return VB2_SIGN_DATA_DIGEST_EXTEND; |
| 148 | } |
| 149 | |
| 150 | if (vb2_digest_finalize(&dc, sig_digest + info_size, digest_size)) { |
| 151 | free(sig_digest); |
| 152 | return VB2_SIGN_DATA_DIGEST_FINALIZE; |
| 153 | } |
| 154 | |
| 155 | /* Allocate signature buffer and copy header */ |
Randall Spangler | 45562fb | 2014-12-01 15:06:53 -0800 | [diff] [blame] | 156 | buf = calloc(1, s.c.total_size); |
Randall Spangler | c644a8c | 2014-11-21 11:04:36 -0800 | [diff] [blame] | 157 | memcpy(buf, &s, sizeof(s)); |
| 158 | |
| 159 | /* strcpy() is ok because we allocated buffer based on desc length */ |
| 160 | if (desc) |
| 161 | strcpy((char *)buf + s.c.fixed_size, desc); |
| 162 | |
| 163 | if (s.sig_alg == VB2_SIG_NONE) { |
| 164 | /* Bare hash signature is just the digest */ |
| 165 | memcpy(buf + s.sig_offset, sig_digest, sig_digest_size); |
| 166 | } else { |
| 167 | /* RSA-encrypt the signature */ |
| 168 | if (RSA_private_encrypt(sig_digest_size, |
| 169 | sig_digest, |
| 170 | buf + s.sig_offset, |
| 171 | key->rsa_private_key, |
| 172 | RSA_PKCS1_PADDING) == -1) { |
| 173 | free(sig_digest); |
| 174 | free(buf); |
| 175 | return VB2_SIGN_DATA_RSA_ENCRYPT; |
| 176 | } |
| 177 | } |
| 178 | |
| 179 | free(sig_digest); |
Randall Spangler | 308d254 | 2014-12-04 09:54:37 -0800 | [diff] [blame] | 180 | *sig_ptr = (struct vb2_signature *)buf; |
Randall Spangler | c644a8c | 2014-11-21 11:04:36 -0800 | [diff] [blame] | 181 | return VB2_SUCCESS; |
| 182 | } |
| 183 | |
| 184 | int vb2_sig_size_for_key(uint32_t *size_ptr, |
| 185 | const struct vb2_private_key *key, |
| 186 | const char *desc) |
| 187 | { |
| 188 | uint32_t size = vb2_sig_size(key->sig_alg, key->hash_alg); |
| 189 | |
| 190 | if (!size) |
| 191 | return VB2_ERROR_SIG_SIZE_FOR_KEY; |
| 192 | |
Randall Spangler | 308d254 | 2014-12-04 09:54:37 -0800 | [diff] [blame] | 193 | size += sizeof(struct vb2_signature); |
Randall Spangler | c644a8c | 2014-11-21 11:04:36 -0800 | [diff] [blame] | 194 | size += vb2_desc_size(desc ? desc : key->desc); |
| 195 | |
| 196 | *size_ptr = size; |
| 197 | return VB2_SUCCESS; |
| 198 | } |
| 199 | |
| 200 | int vb2_sig_size_for_keys(uint32_t *size_ptr, |
| 201 | const struct vb2_private_key **key_list, |
| 202 | uint32_t key_count) |
| 203 | { |
| 204 | uint32_t total = 0, size = 0; |
| 205 | int rv, i; |
| 206 | |
| 207 | *size_ptr = 0; |
| 208 | |
| 209 | for (i = 0; i < key_count; i++) { |
| 210 | rv = vb2_sig_size_for_key(&size, key_list[i], NULL); |
| 211 | if (rv) |
| 212 | return rv; |
| 213 | total += size; |
| 214 | } |
| 215 | |
| 216 | *size_ptr = total; |
| 217 | return VB2_SUCCESS; |
| 218 | } |
| 219 | |
| 220 | int vb2_sign_object(uint8_t *buf, |
| 221 | uint32_t sig_offset, |
| 222 | const struct vb2_private_key *key, |
| 223 | const char *desc) |
| 224 | { |
| 225 | struct vb2_struct_common *c = (struct vb2_struct_common *)buf; |
Randall Spangler | 308d254 | 2014-12-04 09:54:37 -0800 | [diff] [blame] | 226 | struct vb2_signature *sig = NULL; |
Randall Spangler | c644a8c | 2014-11-21 11:04:36 -0800 | [diff] [blame] | 227 | int rv; |
| 228 | |
| 229 | rv = vb2_sign_data(&sig, buf, sig_offset, key, desc); |
| 230 | if (rv) |
| 231 | return rv; |
| 232 | |
| 233 | if (sig_offset + sig->c.total_size > c->total_size) { |
| 234 | free(sig); |
| 235 | return VB2_SIGN_OBJECT_OVERFLOW; |
| 236 | } |
| 237 | |
| 238 | memcpy(buf + sig_offset, sig, sig->c.total_size); |
| 239 | free(sig); |
| 240 | |
| 241 | return VB2_SUCCESS; |
| 242 | } |
| 243 | |
| 244 | int vb2_sign_object_multiple(uint8_t *buf, |
| 245 | uint32_t sig_offset, |
| 246 | const struct vb2_private_key **key_list, |
| 247 | uint32_t key_count) |
| 248 | { |
| 249 | struct vb2_struct_common *c = (struct vb2_struct_common *)buf; |
| 250 | uint32_t sig_next = sig_offset; |
| 251 | int rv, i; |
| 252 | |
| 253 | for (i = 0; i < key_count; i++) { |
Randall Spangler | 308d254 | 2014-12-04 09:54:37 -0800 | [diff] [blame] | 254 | struct vb2_signature *sig = NULL; |
Randall Spangler | c644a8c | 2014-11-21 11:04:36 -0800 | [diff] [blame] | 255 | |
| 256 | rv = vb2_sign_data(&sig, buf, sig_offset, key_list[i], NULL); |
| 257 | if (rv) |
| 258 | return rv; |
| 259 | |
| 260 | if (sig_next + sig->c.total_size > c->total_size) { |
| 261 | free(sig); |
| 262 | return VB2_SIGN_OBJECT_OVERFLOW; |
| 263 | } |
| 264 | |
| 265 | memcpy(buf + sig_next, sig, sig->c.total_size); |
| 266 | sig_next += sig->c.total_size; |
| 267 | free(sig); |
| 268 | } |
| 269 | |
| 270 | return VB2_SUCCESS; |
| 271 | } |