| /* |
| * Testing tool for ASN.1 routines |
| * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi> |
| * |
| * This software may be distributed under the terms of the BSD license. |
| * See README for more details. |
| */ |
| |
| #include "includes.h" |
| |
| #include "common.h" |
| #include "tls/asn1.h" |
| |
| extern int wpa_debug_level; |
| |
| |
| static const char * asn1_class_str(int class) |
| { |
| switch (class) { |
| case ASN1_CLASS_UNIVERSAL: |
| return "Universal"; |
| case ASN1_CLASS_APPLICATION: |
| return "Application"; |
| case ASN1_CLASS_CONTEXT_SPECIFIC: |
| return "Context-specific"; |
| case ASN1_CLASS_PRIVATE: |
| return "Private"; |
| default: |
| return "?"; |
| } |
| } |
| |
| |
| int asn1_parse(const u8 *buf, size_t len, int level) |
| { |
| const u8 *pos, *prev, *end; |
| char prefix[10], str[100]; |
| int _level; |
| struct asn1_hdr hdr; |
| struct asn1_oid oid; |
| u8 tmp; |
| |
| _level = level; |
| if ((size_t) _level > sizeof(prefix) - 1) |
| _level = sizeof(prefix) - 1; |
| memset(prefix, ' ', _level); |
| prefix[_level] = '\0'; |
| |
| pos = buf; |
| end = buf + len; |
| |
| while (pos < end) { |
| if (asn1_get_next(pos, end - pos, &hdr) < 0) |
| return -1; |
| |
| prev = pos; |
| pos = hdr.payload; |
| |
| wpa_printf(MSG_MSGDUMP, "ASN.1:%s Class %d(%s) P/C %d(%s) " |
| "Tag %u Length %u", |
| prefix, hdr.class, asn1_class_str(hdr.class), |
| hdr.constructed, |
| hdr.constructed ? "Constructed" : "Primitive", |
| hdr.tag, hdr.length); |
| |
| if (hdr.class == ASN1_CLASS_CONTEXT_SPECIFIC && |
| hdr.constructed) { |
| if (asn1_parse(pos, hdr.length, level + 1) < 0) |
| return -1; |
| pos += hdr.length; |
| } |
| |
| if (hdr.class != ASN1_CLASS_UNIVERSAL) |
| continue; |
| |
| switch (hdr.tag) { |
| case ASN1_TAG_EOC: |
| if (hdr.length) { |
| wpa_printf(MSG_DEBUG, "ASN.1: Non-zero " |
| "end-of-contents length (%u)", |
| hdr.length); |
| return -1; |
| } |
| wpa_printf(MSG_MSGDUMP, "ASN.1:%s EOC", prefix); |
| break; |
| case ASN1_TAG_BOOLEAN: |
| if (hdr.length != 1) { |
| wpa_printf(MSG_DEBUG, "ASN.1: Unexpected " |
| "Boolean length (%u)", hdr.length); |
| return -1; |
| } |
| tmp = *pos++; |
| wpa_printf(MSG_MSGDUMP, "ASN.1:%s Boolean %s", |
| prefix, tmp ? "TRUE" : "FALSE"); |
| break; |
| case ASN1_TAG_INTEGER: |
| wpa_hexdump(MSG_MSGDUMP, "ASN.1: INTEGER", |
| pos, hdr.length); |
| pos += hdr.length; |
| break; |
| case ASN1_TAG_BITSTRING: |
| wpa_hexdump(MSG_MSGDUMP, "ASN.1: BitString", |
| pos, hdr.length); |
| pos += hdr.length; |
| break; |
| case ASN1_TAG_OCTETSTRING: |
| wpa_hexdump(MSG_MSGDUMP, "ASN.1: OctetString", |
| pos, hdr.length); |
| pos += hdr.length; |
| break; |
| case ASN1_TAG_NULL: |
| if (hdr.length) { |
| wpa_printf(MSG_DEBUG, "ASN.1: Non-zero Null " |
| "length (%u)", hdr.length); |
| return -1; |
| } |
| wpa_printf(MSG_MSGDUMP, "ASN.1:%s Null", prefix); |
| break; |
| case ASN1_TAG_OID: |
| if (asn1_get_oid(prev, end - prev, &oid, &prev) < 0) { |
| wpa_printf(MSG_DEBUG, "ASN.1: Invalid OID"); |
| return -1; |
| } |
| asn1_oid_to_str(&oid, str, sizeof(str)); |
| wpa_printf(MSG_DEBUG, "ASN.1:%s OID %s", prefix, str); |
| pos += hdr.length; |
| break; |
| case ANS1_TAG_RELATIVE_OID: |
| wpa_hexdump(MSG_MSGDUMP, "ASN.1: Relative OID", |
| pos, hdr.length); |
| pos += hdr.length; |
| break; |
| case ASN1_TAG_SEQUENCE: |
| wpa_printf(MSG_MSGDUMP, "ASN.1:%s SEQUENCE", prefix); |
| if (asn1_parse(pos, hdr.length, level + 1) < 0) |
| return -1; |
| pos += hdr.length; |
| break; |
| case ASN1_TAG_SET: |
| wpa_printf(MSG_MSGDUMP, "ASN.1:%s SET", prefix); |
| if (asn1_parse(pos, hdr.length, level + 1) < 0) |
| return -1; |
| pos += hdr.length; |
| break; |
| case ASN1_TAG_PRINTABLESTRING: |
| wpa_hexdump_ascii(MSG_MSGDUMP, |
| "ASN.1: PrintableString", |
| pos, hdr.length); |
| pos += hdr.length; |
| break; |
| case ASN1_TAG_IA5STRING: |
| wpa_hexdump_ascii(MSG_MSGDUMP, "ASN.1: IA5String", |
| pos, hdr.length); |
| pos += hdr.length; |
| break; |
| case ASN1_TAG_UTCTIME: |
| wpa_hexdump_ascii(MSG_MSGDUMP, "ASN.1: UTCTIME", |
| pos, hdr.length); |
| pos += hdr.length; |
| break; |
| case ASN1_TAG_VISIBLESTRING: |
| wpa_hexdump_ascii(MSG_MSGDUMP, "ASN.1: VisibleString", |
| pos, hdr.length); |
| pos += hdr.length; |
| break; |
| default: |
| wpa_printf(MSG_DEBUG, "ASN.1: Unknown tag %d", |
| hdr.tag); |
| return -1; |
| } |
| } |
| |
| return 0; |
| } |
| |
| |
| int main(int argc, char *argv[]) |
| { |
| FILE *f; |
| u8 buf[3000]; |
| size_t len; |
| |
| wpa_debug_level = 0; |
| |
| f = fopen(argv[1], "rb"); |
| if (f == NULL) |
| return -1; |
| len = fread(buf, 1, sizeof(buf), f); |
| fclose(f); |
| |
| if (asn1_parse(buf, len, 0) < 0) |
| printf("Failed to parse DER ASN.1\n"); |
| |
| printf("\n\n"); |
| |
| return 0; |
| } |