Richard Levitte | 1d39620 | 2020-03-31 16:54:43 +0200 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2020 The OpenSSL Project Authors. All Rights Reserved. |
| 3 | * |
| 4 | * Licensed under the Apache License 2.0 (the "License"). You may not use |
| 5 | * this file except in compliance with the License. You can obtain a copy |
| 6 | * in the file LICENSE in the source distribution or at |
| 7 | * https://www.openssl.org/source/license.html |
| 8 | */ |
| 9 | |
| 10 | #include <stdlib.h> |
| 11 | #include <string.h> |
| 12 | #include "internal/cryptlib.h" |
| 13 | #include "internal/der.h" |
| 14 | #include "crypto/bn.h" |
| 15 | |
| 16 | static int int_start_context(WPACKET *pkt, int tag) |
| 17 | { |
| 18 | if (tag < 0) |
| 19 | return 1; |
| 20 | if (!ossl_assert(tag <= 30)) |
| 21 | return 0; |
| 22 | return WPACKET_start_sub_packet(pkt); |
| 23 | } |
| 24 | |
| 25 | static int int_end_context(WPACKET *pkt, int tag) |
| 26 | { |
Richard Levitte | 2275ff6 | 2020-05-02 13:33:24 +0200 | [diff] [blame] | 27 | /* |
| 28 | * If someone set the flag WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH on this |
| 29 | * sub-packet and this sub-packet has nothing written to it, the DER length |
| 30 | * will not be written, and the total written size will be unchanged before |
| 31 | * and after WPACKET_close(). We use size1 and size2 to determine if |
| 32 | * anything was written, and only write our tag if it has. |
| 33 | * |
| 34 | */ |
| 35 | size_t size1, size2; |
| 36 | |
Richard Levitte | 1d39620 | 2020-03-31 16:54:43 +0200 | [diff] [blame] | 37 | if (tag < 0) |
| 38 | return 1; |
| 39 | if (!ossl_assert(tag <= 30)) |
| 40 | return 0; |
Richard Levitte | 6c6b20d | 2020-07-27 18:39:51 +0200 | [diff] [blame] | 41 | |
| 42 | /* Context specific are normally (?) constructed */ |
| 43 | tag |= DER_F_CONSTRUCTED | DER_C_CONTEXT; |
| 44 | |
Richard Levitte | 2275ff6 | 2020-05-02 13:33:24 +0200 | [diff] [blame] | 45 | return WPACKET_get_total_written(pkt, &size1) |
| 46 | && WPACKET_close(pkt) |
| 47 | && WPACKET_get_total_written(pkt, &size2) |
Richard Levitte | 6c6b20d | 2020-07-27 18:39:51 +0200 | [diff] [blame] | 48 | && (size1 == size2 || WPACKET_put_bytes_u8(pkt, tag)); |
Richard Levitte | 1d39620 | 2020-03-31 16:54:43 +0200 | [diff] [blame] | 49 | } |
| 50 | |
Pauli | a55b00b | 2020-09-30 12:15:12 +1000 | [diff] [blame] | 51 | int ossl_DER_w_precompiled(WPACKET *pkt, int tag, |
| 52 | const unsigned char *precompiled, |
| 53 | size_t precompiled_n) |
Richard Levitte | 1d39620 | 2020-03-31 16:54:43 +0200 | [diff] [blame] | 54 | { |
| 55 | return int_start_context(pkt, tag) |
| 56 | && WPACKET_memcpy(pkt, precompiled, precompiled_n) |
| 57 | && int_end_context(pkt, tag); |
| 58 | } |
| 59 | |
Pauli | a55b00b | 2020-09-30 12:15:12 +1000 | [diff] [blame] | 60 | int ossl_DER_w_boolean(WPACKET *pkt, int tag, int b) |
Richard Levitte | 1d39620 | 2020-03-31 16:54:43 +0200 | [diff] [blame] | 61 | { |
| 62 | return int_start_context(pkt, tag) |
| 63 | && WPACKET_start_sub_packet(pkt) |
| 64 | && (!b || WPACKET_put_bytes_u8(pkt, 0xFF)) |
| 65 | && !WPACKET_close(pkt) |
| 66 | && !WPACKET_put_bytes_u8(pkt, DER_P_BOOLEAN) |
| 67 | && int_end_context(pkt, tag); |
| 68 | } |
| 69 | |
Pauli | a55b00b | 2020-09-30 12:15:12 +1000 | [diff] [blame] | 70 | int ossl_DER_w_octet_string(WPACKET *pkt, int tag, |
| 71 | const unsigned char *data, size_t data_n) |
Shane Lontis | e5b2cd5 | 2020-08-04 12:18:51 +1000 | [diff] [blame] | 72 | { |
| 73 | return int_start_context(pkt, tag) |
| 74 | && WPACKET_start_sub_packet(pkt) |
| 75 | && WPACKET_memcpy(pkt, data, data_n) |
| 76 | && WPACKET_close(pkt) |
| 77 | && WPACKET_put_bytes_u8(pkt, DER_P_OCTET_STRING) |
| 78 | && int_end_context(pkt, tag); |
| 79 | } |
| 80 | |
Pauli | a55b00b | 2020-09-30 12:15:12 +1000 | [diff] [blame] | 81 | int ossl_DER_w_octet_string_uint32(WPACKET *pkt, int tag, uint32_t value) |
Shane Lontis | e5b2cd5 | 2020-08-04 12:18:51 +1000 | [diff] [blame] | 82 | { |
| 83 | unsigned char tmp[4] = { 0, 0, 0, 0 }; |
| 84 | unsigned char *pbuf = tmp + (sizeof(tmp) - 1); |
| 85 | |
| 86 | while (value > 0) { |
| 87 | *pbuf-- = (value & 0xFF); |
| 88 | value >>= 8; |
| 89 | } |
Pauli | a55b00b | 2020-09-30 12:15:12 +1000 | [diff] [blame] | 90 | return ossl_DER_w_octet_string(pkt, tag, tmp, sizeof(tmp)); |
Shane Lontis | e5b2cd5 | 2020-08-04 12:18:51 +1000 | [diff] [blame] | 91 | } |
| 92 | |
Richard Levitte | 1d39620 | 2020-03-31 16:54:43 +0200 | [diff] [blame] | 93 | static int int_der_w_integer(WPACKET *pkt, int tag, |
| 94 | int (*put_bytes)(WPACKET *pkt, const void *v, |
| 95 | unsigned int *top_byte), |
| 96 | const void *v) |
| 97 | { |
| 98 | unsigned int top_byte = 0; |
| 99 | |
| 100 | return int_start_context(pkt, tag) |
| 101 | && WPACKET_start_sub_packet(pkt) |
| 102 | && put_bytes(pkt, v, &top_byte) |
| 103 | && ((top_byte & 0x80) == 0 || WPACKET_put_bytes_u8(pkt, 0)) |
| 104 | && WPACKET_close(pkt) |
| 105 | && WPACKET_put_bytes_u8(pkt, DER_P_INTEGER) |
| 106 | && int_end_context(pkt, tag); |
| 107 | } |
| 108 | |
| 109 | static int int_put_bytes_ulong(WPACKET *pkt, const void *v, |
| 110 | unsigned int *top_byte) |
| 111 | { |
| 112 | const unsigned long *value = v; |
| 113 | unsigned long tmp = *value; |
| 114 | size_t n = 0; |
| 115 | |
| 116 | while (tmp != 0) { |
| 117 | n++; |
| 118 | *top_byte = (tmp & 0xFF); |
| 119 | tmp >>= 8; |
| 120 | } |
| 121 | if (n == 0) |
| 122 | n = 1; |
| 123 | |
| 124 | return WPACKET_put_bytes__(pkt, *value, n); |
| 125 | } |
| 126 | |
| 127 | /* For integers, we only support unsigned values for now */ |
Pauli | a55b00b | 2020-09-30 12:15:12 +1000 | [diff] [blame] | 128 | int ossl_DER_w_ulong(WPACKET *pkt, int tag, unsigned long v) |
Richard Levitte | 1d39620 | 2020-03-31 16:54:43 +0200 | [diff] [blame] | 129 | { |
| 130 | return int_der_w_integer(pkt, tag, int_put_bytes_ulong, &v); |
| 131 | } |
| 132 | |
| 133 | static int int_put_bytes_bn(WPACKET *pkt, const void *v, |
| 134 | unsigned int *top_byte) |
| 135 | { |
| 136 | unsigned char *p = NULL; |
| 137 | size_t n = BN_num_bytes(v); |
| 138 | |
| 139 | /* The BIGNUM limbs are in LE order */ |
| 140 | *top_byte = |
| 141 | ((bn_get_words(v) [(n - 1) / BN_BYTES]) >> (8 * ((n - 1) % BN_BYTES))) |
| 142 | & 0xFF; |
| 143 | |
| 144 | if (!WPACKET_allocate_bytes(pkt, n, &p)) |
| 145 | return 0; |
| 146 | if (p != NULL) |
| 147 | BN_bn2bin(v, p); |
| 148 | return 1; |
| 149 | } |
| 150 | |
Pauli | a55b00b | 2020-09-30 12:15:12 +1000 | [diff] [blame] | 151 | int ossl_DER_w_bn(WPACKET *pkt, int tag, const BIGNUM *v) |
Richard Levitte | 1d39620 | 2020-03-31 16:54:43 +0200 | [diff] [blame] | 152 | { |
| 153 | if (v == NULL || BN_is_negative(v)) |
| 154 | return 0; |
| 155 | if (BN_is_zero(v)) |
Pauli | a55b00b | 2020-09-30 12:15:12 +1000 | [diff] [blame] | 156 | return ossl_DER_w_ulong(pkt, tag, 0); |
Richard Levitte | 1d39620 | 2020-03-31 16:54:43 +0200 | [diff] [blame] | 157 | |
| 158 | return int_der_w_integer(pkt, tag, int_put_bytes_bn, v); |
| 159 | } |
| 160 | |
Pauli | a55b00b | 2020-09-30 12:15:12 +1000 | [diff] [blame] | 161 | int ossl_DER_w_null(WPACKET *pkt, int tag) |
Richard Levitte | 1d39620 | 2020-03-31 16:54:43 +0200 | [diff] [blame] | 162 | { |
| 163 | return int_start_context(pkt, tag) |
| 164 | && WPACKET_start_sub_packet(pkt) |
| 165 | && WPACKET_close(pkt) |
| 166 | && WPACKET_put_bytes_u8(pkt, DER_P_NULL) |
| 167 | && int_end_context(pkt, tag); |
| 168 | } |
| 169 | |
| 170 | /* Constructed things need a start and an end */ |
Pauli | a55b00b | 2020-09-30 12:15:12 +1000 | [diff] [blame] | 171 | int ossl_DER_w_begin_sequence(WPACKET *pkt, int tag) |
Richard Levitte | 1d39620 | 2020-03-31 16:54:43 +0200 | [diff] [blame] | 172 | { |
| 173 | return int_start_context(pkt, tag) |
| 174 | && WPACKET_start_sub_packet(pkt); |
| 175 | } |
| 176 | |
Pauli | a55b00b | 2020-09-30 12:15:12 +1000 | [diff] [blame] | 177 | int ossl_DER_w_end_sequence(WPACKET *pkt, int tag) |
Richard Levitte | 1d39620 | 2020-03-31 16:54:43 +0200 | [diff] [blame] | 178 | { |
Richard Levitte | 2275ff6 | 2020-05-02 13:33:24 +0200 | [diff] [blame] | 179 | /* |
| 180 | * If someone set the flag WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH on this |
| 181 | * sub-packet and this sub-packet has nothing written to it, the DER length |
| 182 | * will not be written, and the total written size will be unchanged before |
| 183 | * and after WPACKET_close(). We use size1 and size2 to determine if |
| 184 | * anything was written, and only write our tag if it has. |
| 185 | * |
| 186 | * Because we know that int_end_context() needs to do the same check, |
| 187 | * we reproduce this flag if the written length was unchanged, or we will |
| 188 | * have an erroneous context tag. |
| 189 | */ |
| 190 | size_t size1, size2; |
| 191 | |
| 192 | return WPACKET_get_total_written(pkt, &size1) |
| 193 | && WPACKET_close(pkt) |
| 194 | && WPACKET_get_total_written(pkt, &size2) |
| 195 | && (size1 == size2 |
| 196 | ? WPACKET_set_flags(pkt, WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH) |
| 197 | : WPACKET_put_bytes_u8(pkt, DER_F_CONSTRUCTED | DER_P_SEQUENCE)) |
Richard Levitte | 1d39620 | 2020-03-31 16:54:43 +0200 | [diff] [blame] | 198 | && int_end_context(pkt, tag); |
| 199 | } |