1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 /* SPDX-License-Identifier: Unlicense */
3 #include "tomcrypt_private.h"
4 
5 /**
6   @file der_encode_asn1_identifier.c
7   ASN.1 DER, encode the ASN.1 Identifier, Steffen Jaeckel
8 */
9 
10 #ifdef LTC_DER
11 /**
12   Encode the ASN.1 Identifier
13   @param id       The ASN.1 Identifer to encode
14   @param out      Where to write the identifier to
15   @param outlen   [in/out] The size of out available/written
16   @return CRYPT_OK if successful
17 */
der_encode_asn1_identifier(const ltc_asn1_list * id,unsigned char * out,unsigned long * outlen)18 int der_encode_asn1_identifier(const ltc_asn1_list *id, unsigned char *out, unsigned long *outlen)
19 {
20    ulong64 tmp;
21    unsigned long tag_len;
22 
23    LTC_ARGCHK(id  != NULL);
24    LTC_ARGCHK(outlen != NULL);
25 
26    if (id->type != LTC_ASN1_CUSTOM_TYPE) {
27       if ((unsigned)id->type >= der_asn1_type_to_identifier_map_sz) {
28          return CRYPT_INVALID_ARG;
29       }
30       if (der_asn1_type_to_identifier_map[id->type] == -1) {
31          return CRYPT_INVALID_ARG;
32       }
33       if (out != NULL) {
34          *out = der_asn1_type_to_identifier_map[id->type];
35       }
36       *outlen = 1;
37       return CRYPT_OK;
38    }
39    if (id->klass < LTC_ASN1_CL_UNIVERSAL || id->klass > LTC_ASN1_CL_PRIVATE) {
40       return CRYPT_INVALID_ARG;
41    }
42    if (id->pc < LTC_ASN1_PC_PRIMITIVE || id->pc > LTC_ASN1_PC_CONSTRUCTED) {
43       return CRYPT_INVALID_ARG;
44    }
45    if (id->tag > (ULONG_MAX >> (8 + 7))) {
46       return CRYPT_INVALID_ARG;
47    }
48 
49    if (out != NULL) {
50       if (*outlen < 1) {
51          return CRYPT_BUFFER_OVERFLOW;
52       }
53 
54       out[0] = id->klass << 6 | id->pc << 5;
55    }
56 
57    if (id->tag < 0x1f) {
58       if (out != NULL) {
59          out[0] |= id->tag & 0x1f;
60       }
61       *outlen = 1;
62    } else {
63       tag_len = 0;
64       tmp = id->tag;
65       do {
66          tag_len++;
67          tmp >>= 7;
68       } while (tmp);
69 
70       if (out != NULL) {
71          if (*outlen < tag_len + 1) {
72             return CRYPT_BUFFER_OVERFLOW;
73          }
74          out[0] |= 0x1f;
75          for (tmp = 1; tmp <= tag_len; ++tmp) {
76             out[tmp] = ((id->tag >> (7 * (tag_len - tmp))) & 0x7f) | 0x80;
77          }
78          out[tag_len] &= ~0x80;
79       }
80       *outlen = tag_len + 1;
81    }
82 
83    return CRYPT_OK;
84 }
85 
86 #endif
87