1 /* 2 * Copyright 2020-2022 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 { 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 37 if (tag < 0) 38 return 1; 39 if (!ossl_assert(tag <= 30)) 40 return 0; 41 42 /* Context specific are normally (?) constructed */ 43 tag |= DER_F_CONSTRUCTED | DER_C_CONTEXT; 44 45 return WPACKET_get_total_written(pkt, &size1) 46 && WPACKET_close(pkt) 47 && WPACKET_get_total_written(pkt, &size2) 48 && (size1 == size2 || WPACKET_put_bytes_u8(pkt, tag)); 49 } 50 51 int ossl_DER_w_precompiled(WPACKET *pkt, int tag, 52 const unsigned char *precompiled, 53 size_t precompiled_n) 54 { 55 return int_start_context(pkt, tag) 56 && WPACKET_memcpy(pkt, precompiled, precompiled_n) 57 && int_end_context(pkt, tag); 58 } 59 60 int ossl_DER_w_boolean(WPACKET *pkt, int tag, int b) 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 70 int ossl_DER_w_octet_string(WPACKET *pkt, int tag, 71 const unsigned char *data, size_t data_n) 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 81 int ossl_DER_w_octet_string_uint32(WPACKET *pkt, int tag, uint32_t value) 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 } 90 return ossl_DER_w_octet_string(pkt, tag, tmp, sizeof(tmp)); 91 } 92 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_uint32(WPACKET *pkt, const void *v, 110 unsigned int *top_byte) 111 { 112 const uint32_t *value = v; 113 uint32_t 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 */ 128 int ossl_DER_w_uint32(WPACKET *pkt, int tag, uint32_t v) 129 { 130 return int_der_w_integer(pkt, tag, int_put_bytes_uint32, &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 151 int ossl_DER_w_bn(WPACKET *pkt, int tag, const BIGNUM *v) 152 { 153 if (v == NULL || BN_is_negative(v)) 154 return 0; 155 if (BN_is_zero(v)) 156 return ossl_DER_w_uint32(pkt, tag, 0); 157 158 return int_der_w_integer(pkt, tag, int_put_bytes_bn, v); 159 } 160 161 int ossl_DER_w_null(WPACKET *pkt, int tag) 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 */ 171 int ossl_DER_w_begin_sequence(WPACKET *pkt, int tag) 172 { 173 return int_start_context(pkt, tag) 174 && WPACKET_start_sub_packet(pkt); 175 } 176 177 int ossl_DER_w_end_sequence(WPACKET *pkt, int tag) 178 { 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)) 198 && int_end_context(pkt, tag); 199 } 200