1 /* $OpenBSD: asn1complex.c,v 1.4 2022/09/05 21:06:31 tb Exp $ */ 2 /* 3 * Copyright (c) 2017, 2021 Joel Sing <jsing@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <openssl/asn1.h> 19 #include <openssl/asn1t.h> 20 #include <openssl/err.h> 21 22 #include <err.h> 23 #include <stdio.h> 24 #include <string.h> 25 26 static void 27 hexdump(const unsigned char *buf, size_t len) 28 { 29 size_t i; 30 31 for (i = 1; i <= len; i++) 32 fprintf(stderr, " 0x%02hhx,%s", buf[i - 1], i % 8 ? "" : "\n"); 33 34 fprintf(stderr, "\n"); 35 } 36 37 static int 38 asn1_compare_bytes(const char *label, const unsigned char *d1, int len1, 39 const unsigned char *d2, int len2) 40 { 41 if (len1 != len2) { 42 fprintf(stderr, "FAIL: %s - byte lengths differ " 43 "(%d != %d)\n", label, len1, len2); 44 return 0; 45 } 46 if (memcmp(d1, d2, len1) != 0) { 47 fprintf(stderr, "FAIL: %s - bytes differ\n", label); 48 fprintf(stderr, "Got:\n"); 49 hexdump(d1, len1); 50 fprintf(stderr, "Want:\n"); 51 hexdump(d2, len2); 52 return 0; 53 } 54 return 1; 55 } 56 57 /* Constructed octet string with length 12. */ 58 const uint8_t asn1_constructed_basic_ber[] = { 59 0x24, 0x0c, 60 0x04, 0x01, 0x01, 61 0x04, 0x02, 0x01, 0x02, 62 0x04, 0x03, 0x01, 0x02, 0x03 63 }; 64 const uint8_t asn1_constructed_basic_content[] = { 65 0x01, 0x01, 0x02, 0x01, 0x02, 0x03, 66 }; 67 68 /* Nested constructed octet string. */ 69 const uint8_t asn1_constructed_nested_ber[] = { 70 0x24, 0x1a, 71 0x04, 0x01, 0x01, 72 0x24, 0x15, 73 0x04, 0x02, 0x02, 0x03, 74 0x24, 0x0f, 75 0x24, 0x0d, 76 0x04, 0x03, 0x04, 0x05, 0x06, 77 0x24, 0x06, 78 0x24, 0x04, 79 0x04, 0x02, 0x07, 0x08, 80 }; 81 const uint8_t asn1_constructed_nested_content[] = { 82 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 83 }; 84 85 /* Deeply nested constructed octet string. */ 86 const uint8_t asn1_constructed_deep_nested_ber[] = { 87 0x24, 0x1b, 88 0x04, 0x01, 0x01, 89 0x24, 0x16, 90 0x04, 0x02, 0x02, 0x03, 91 0x24, 0x10, 92 0x24, 0x0e, 93 0x04, 0x03, 0x04, 0x05, 0x06, 94 0x24, 0x07, 95 0x24, 0x05, 96 0x24, 0x03, 97 0x04, 0x01, 0x07, 98 }; 99 100 /* Constructed octet string with indefinite length. */ 101 const uint8_t asn1_constructed_indefinite_ber[] = { 102 0x24, 0x80, 103 0x04, 0x01, 0x01, 104 0x04, 0x02, 0x01, 0x02, 105 0x04, 0x03, 0x01, 0x02, 0x03, 106 0x00, 0x00, 107 }; 108 const uint8_t asn1_constructed_indefinite_content[] = { 109 0x01, 0x01, 0x02, 0x01, 0x02, 0x03, 110 }; 111 112 struct asn1_constructed_test { 113 const char *name; 114 const uint8_t *asn1; 115 size_t asn1_len; 116 const uint8_t *want; 117 size_t want_len; 118 int want_error; 119 int valid; 120 }; 121 122 const struct asn1_constructed_test asn1_constructed_tests[] = { 123 { 124 .name = "basic constructed", 125 .asn1 = asn1_constructed_basic_ber, 126 .asn1_len = sizeof(asn1_constructed_basic_ber), 127 .want = asn1_constructed_basic_content, 128 .want_len = sizeof(asn1_constructed_basic_content), 129 .valid = 1, 130 }, 131 { 132 .name = "nested constructed", 133 .asn1 = asn1_constructed_nested_ber, 134 .asn1_len = sizeof(asn1_constructed_nested_ber), 135 .want = asn1_constructed_nested_content, 136 .want_len = sizeof(asn1_constructed_nested_content), 137 .valid = 1, 138 }, 139 { 140 .name = "deep nested constructed", 141 .asn1 = asn1_constructed_deep_nested_ber, 142 .asn1_len = sizeof(asn1_constructed_deep_nested_ber), 143 .want_error = ASN1_R_NESTED_ASN1_STRING, 144 .valid = 0, 145 }, 146 { 147 .name = "indefinite length constructed", 148 .asn1 = asn1_constructed_indefinite_ber, 149 .asn1_len = sizeof(asn1_constructed_indefinite_ber), 150 .want = asn1_constructed_indefinite_content, 151 .want_len = sizeof(asn1_constructed_indefinite_content), 152 .valid = 1, 153 }, 154 }; 155 156 #define N_CONSTRUCTED_TESTS \ 157 (sizeof(asn1_constructed_tests) / sizeof(*asn1_constructed_tests)) 158 159 static int 160 do_asn1_constructed_test(const struct asn1_constructed_test *act) 161 { 162 ASN1_OCTET_STRING *aos = NULL; 163 const uint8_t *p; 164 long err; 165 int failed = 1; 166 167 ERR_clear_error(); 168 169 p = act->asn1; 170 aos = d2i_ASN1_OCTET_STRING(NULL, &p, act->asn1_len); 171 if (!act->valid) { 172 if (aos != NULL) { 173 fprintf(stderr, "FAIL: invalid ASN.1 decoded\n"); 174 goto failed; 175 } 176 if (act->want_error != 0) { 177 err = ERR_peek_error(); 178 if (ERR_GET_REASON(err) != act->want_error) { 179 fprintf(stderr, "FAIL: got error reason %d," 180 "want %d", ERR_GET_REASON(err), 181 act->want_error); 182 goto failed; 183 } 184 } 185 goto done; 186 } 187 if (aos == NULL) { 188 fprintf(stderr, "FAIL: failed to decode ASN.1 constructed " 189 "octet string\n"); 190 ERR_print_errors_fp(stderr); 191 goto failed; 192 } 193 if (!asn1_compare_bytes(act->name, ASN1_STRING_data(aos), 194 ASN1_STRING_length(aos), act->want, act->want_len)) 195 goto failed; 196 197 done: 198 failed = 0; 199 200 failed: 201 ASN1_OCTET_STRING_free(aos); 202 203 return failed; 204 } 205 206 static int 207 do_asn1_constructed_tests(void) 208 { 209 const struct asn1_constructed_test *act; 210 int failed = 0; 211 size_t i; 212 213 for (i = 0; i < N_CONSTRUCTED_TESTS; i++) { 214 act = &asn1_constructed_tests[i]; 215 failed |= do_asn1_constructed_test(act); 216 } 217 218 return failed; 219 } 220 221 /* Sequence with length. */ 222 const uint8_t asn1_sequence_ber[] = { 223 0x30, 0x16, 224 0x04, 0x01, 0x01, 225 0x04, 0x02, 0x01, 0x02, 226 0x04, 0x03, 0x01, 0x02, 0x03, 227 0x30, 0x80, 0x04, 0x01, 0x01, 0x00, 0x00, 228 0x04, 0x01, 0x01, 229 230 0x04, 0x01, 0x01, /* Trailing data. */ 231 }; 232 233 const uint8_t asn1_sequence_content[] = { 234 0x30, 0x16, 0x04, 0x01, 0x01, 0x04, 0x02, 0x01, 235 0x02, 0x04, 0x03, 0x01, 0x02, 0x03, 0x30, 0x80, 236 0x04, 0x01, 0x01, 0x00, 0x00, 0x04, 0x01, 0x01, 237 }; 238 239 /* Sequence with indefinite length. */ 240 const uint8_t asn1_sequence_indefinite_ber[] = { 241 0x30, 0x80, 242 0x04, 0x01, 0x01, 243 0x04, 0x02, 0x01, 0x02, 244 0x04, 0x03, 0x01, 0x02, 0x03, 245 0x30, 0x80, 0x04, 0x01, 0x01, 0x00, 0x00, 246 0x04, 0x01, 0x01, 247 0x00, 0x00, 248 249 0x04, 0x01, 0x01, /* Trailing data. */ 250 }; 251 252 const uint8_t asn1_sequence_indefinite_content[] = { 253 0x30, 0x80, 0x04, 0x01, 0x01, 0x04, 0x02, 0x01, 254 0x02, 0x04, 0x03, 0x01, 0x02, 0x03, 0x30, 0x80, 255 0x04, 0x01, 0x01, 0x00, 0x00, 0x04, 0x01, 0x01, 256 0x00, 0x00, 257 }; 258 259 static int 260 do_asn1_sequence_string_tests(void) 261 { 262 ASN1_STRING *astr = NULL; 263 const uint8_t *p; 264 long len; 265 int failed = 1; 266 267 ERR_clear_error(); 268 269 /* 270 * Test decoding of sequence with length and indefinite length into 271 * a string - in this case the ASN.1 is not decoded and is stored 272 * directly as the content for the string. 273 */ 274 if ((astr = ASN1_STRING_new()) == NULL) { 275 fprintf(stderr, "FAIL: ASN1_STRING_new() returned NULL\n"); 276 goto failed; 277 } 278 279 p = asn1_sequence_ber; 280 len = sizeof(asn1_sequence_ber); 281 if (ASN1_item_d2i((ASN1_VALUE **)&astr, &p, len, 282 &ASN1_SEQUENCE_it) == NULL) { 283 fprintf(stderr, "FAIL: failed to decode ASN1_SEQUENCE\n"); 284 ERR_print_errors_fp(stderr); 285 goto failed; 286 } 287 288 if (!asn1_compare_bytes("sequence", ASN1_STRING_data(astr), 289 ASN1_STRING_length(astr), asn1_sequence_content, 290 sizeof(asn1_sequence_content))) 291 goto failed; 292 293 p = asn1_sequence_indefinite_ber; 294 len = sizeof(asn1_sequence_indefinite_ber); 295 if (ASN1_item_d2i((ASN1_VALUE **)&astr, &p, len, 296 &ASN1_SEQUENCE_it) == NULL) { 297 fprintf(stderr, "FAIL: failed to decode ASN1_SEQUENCE\n"); 298 ERR_print_errors_fp(stderr); 299 goto failed; 300 } 301 302 if (!asn1_compare_bytes("sequence indefinite", ASN1_STRING_data(astr), 303 ASN1_STRING_length(astr), asn1_sequence_indefinite_content, 304 sizeof(asn1_sequence_indefinite_content))) 305 goto failed; 306 307 failed = 0; 308 309 failed: 310 ASN1_STRING_free(astr); 311 312 return failed; 313 } 314 315 int 316 main(int argc, char **argv) 317 { 318 int failed = 0; 319 320 failed |= do_asn1_constructed_tests(); 321 failed |= do_asn1_sequence_string_tests(); 322 323 return (failed); 324 } 325