1e1051a39Sopenharmony_ci/* 2e1051a39Sopenharmony_ci * Copyright 2000-2021 The OpenSSL Project Authors. All Rights Reserved. 3e1051a39Sopenharmony_ci * 4e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License"). You may not use 5e1051a39Sopenharmony_ci * this file except in compliance with the License. You can obtain a copy 6e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at 7e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html 8e1051a39Sopenharmony_ci */ 9e1051a39Sopenharmony_ci 10e1051a39Sopenharmony_ci#include <stddef.h> 11e1051a39Sopenharmony_ci#include <string.h> 12e1051a39Sopenharmony_ci#include "internal/cryptlib.h" 13e1051a39Sopenharmony_ci#include <openssl/asn1.h> 14e1051a39Sopenharmony_ci#include <openssl/asn1t.h> 15e1051a39Sopenharmony_ci#include <openssl/objects.h> 16e1051a39Sopenharmony_ci#include "crypto/asn1.h" 17e1051a39Sopenharmony_ci#include "asn1_local.h" 18e1051a39Sopenharmony_ci 19e1051a39Sopenharmony_cistatic int asn1_i2d_ex_primitive(const ASN1_VALUE **pval, unsigned char **out, 20e1051a39Sopenharmony_ci const ASN1_ITEM *it, int tag, int aclass); 21e1051a39Sopenharmony_cistatic int asn1_set_seq_out(STACK_OF(const_ASN1_VALUE) *sk, 22e1051a39Sopenharmony_ci unsigned char **out, 23e1051a39Sopenharmony_ci int skcontlen, const ASN1_ITEM *item, 24e1051a39Sopenharmony_ci int do_sort, int iclass); 25e1051a39Sopenharmony_cistatic int asn1_template_ex_i2d(const ASN1_VALUE **pval, unsigned char **out, 26e1051a39Sopenharmony_ci const ASN1_TEMPLATE *tt, int tag, int aclass); 27e1051a39Sopenharmony_cistatic int asn1_item_flags_i2d(const ASN1_VALUE *val, unsigned char **out, 28e1051a39Sopenharmony_ci const ASN1_ITEM *it, int flags); 29e1051a39Sopenharmony_cistatic int asn1_ex_i2c(const ASN1_VALUE **pval, unsigned char *cout, int *putype, 30e1051a39Sopenharmony_ci const ASN1_ITEM *it); 31e1051a39Sopenharmony_ci 32e1051a39Sopenharmony_ci/* 33e1051a39Sopenharmony_ci * Top level i2d equivalents: the 'ndef' variant instructs the encoder to use 34e1051a39Sopenharmony_ci * indefinite length constructed encoding, where appropriate 35e1051a39Sopenharmony_ci */ 36e1051a39Sopenharmony_ci 37e1051a39Sopenharmony_ciint ASN1_item_ndef_i2d(const ASN1_VALUE *val, unsigned char **out, 38e1051a39Sopenharmony_ci const ASN1_ITEM *it) 39e1051a39Sopenharmony_ci{ 40e1051a39Sopenharmony_ci return asn1_item_flags_i2d(val, out, it, ASN1_TFLG_NDEF); 41e1051a39Sopenharmony_ci} 42e1051a39Sopenharmony_ci 43e1051a39Sopenharmony_ciint ASN1_item_i2d(const ASN1_VALUE *val, unsigned char **out, const ASN1_ITEM *it) 44e1051a39Sopenharmony_ci{ 45e1051a39Sopenharmony_ci return asn1_item_flags_i2d(val, out, it, 0); 46e1051a39Sopenharmony_ci} 47e1051a39Sopenharmony_ci 48e1051a39Sopenharmony_ci/* 49e1051a39Sopenharmony_ci * Encode an ASN1 item, this is use by the standard 'i2d' function. 'out' 50e1051a39Sopenharmony_ci * points to a buffer to output the data to. The new i2d has one additional 51e1051a39Sopenharmony_ci * feature. If the output buffer is NULL (i.e. *out == NULL) then a buffer is 52e1051a39Sopenharmony_ci * allocated and populated with the encoding. 53e1051a39Sopenharmony_ci */ 54e1051a39Sopenharmony_ci 55e1051a39Sopenharmony_cistatic int asn1_item_flags_i2d(const ASN1_VALUE *val, unsigned char **out, 56e1051a39Sopenharmony_ci const ASN1_ITEM *it, int flags) 57e1051a39Sopenharmony_ci{ 58e1051a39Sopenharmony_ci if (out != NULL && *out == NULL) { 59e1051a39Sopenharmony_ci unsigned char *p, *buf; 60e1051a39Sopenharmony_ci int len; 61e1051a39Sopenharmony_ci 62e1051a39Sopenharmony_ci len = ASN1_item_ex_i2d(&val, NULL, it, -1, flags); 63e1051a39Sopenharmony_ci if (len <= 0) 64e1051a39Sopenharmony_ci return len; 65e1051a39Sopenharmony_ci if ((buf = OPENSSL_malloc(len)) == NULL) { 66e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE); 67e1051a39Sopenharmony_ci return -1; 68e1051a39Sopenharmony_ci } 69e1051a39Sopenharmony_ci p = buf; 70e1051a39Sopenharmony_ci ASN1_item_ex_i2d(&val, &p, it, -1, flags); 71e1051a39Sopenharmony_ci *out = buf; 72e1051a39Sopenharmony_ci return len; 73e1051a39Sopenharmony_ci } 74e1051a39Sopenharmony_ci 75e1051a39Sopenharmony_ci return ASN1_item_ex_i2d(&val, out, it, -1, flags); 76e1051a39Sopenharmony_ci} 77e1051a39Sopenharmony_ci 78e1051a39Sopenharmony_ci/* 79e1051a39Sopenharmony_ci * Encode an item, taking care of IMPLICIT tagging (if any). This function 80e1051a39Sopenharmony_ci * performs the normal item handling: it can be used in external types. 81e1051a39Sopenharmony_ci */ 82e1051a39Sopenharmony_ci 83e1051a39Sopenharmony_ciint ASN1_item_ex_i2d(const ASN1_VALUE **pval, unsigned char **out, 84e1051a39Sopenharmony_ci const ASN1_ITEM *it, int tag, int aclass) 85e1051a39Sopenharmony_ci{ 86e1051a39Sopenharmony_ci const ASN1_TEMPLATE *tt = NULL; 87e1051a39Sopenharmony_ci int i, seqcontlen, seqlen, ndef = 1; 88e1051a39Sopenharmony_ci const ASN1_EXTERN_FUNCS *ef; 89e1051a39Sopenharmony_ci const ASN1_AUX *aux = it->funcs; 90e1051a39Sopenharmony_ci ASN1_aux_const_cb *asn1_cb = NULL; 91e1051a39Sopenharmony_ci 92e1051a39Sopenharmony_ci if ((it->itype != ASN1_ITYPE_PRIMITIVE) && *pval == NULL) 93e1051a39Sopenharmony_ci return 0; 94e1051a39Sopenharmony_ci 95e1051a39Sopenharmony_ci if (aux != NULL) { 96e1051a39Sopenharmony_ci asn1_cb = ((aux->flags & ASN1_AFLG_CONST_CB) != 0) ? aux->asn1_const_cb 97e1051a39Sopenharmony_ci : (ASN1_aux_const_cb *)aux->asn1_cb; /* backward compatibility */ 98e1051a39Sopenharmony_ci } 99e1051a39Sopenharmony_ci 100e1051a39Sopenharmony_ci switch (it->itype) { 101e1051a39Sopenharmony_ci 102e1051a39Sopenharmony_ci case ASN1_ITYPE_PRIMITIVE: 103e1051a39Sopenharmony_ci if (it->templates) 104e1051a39Sopenharmony_ci return asn1_template_ex_i2d(pval, out, it->templates, 105e1051a39Sopenharmony_ci tag, aclass); 106e1051a39Sopenharmony_ci return asn1_i2d_ex_primitive(pval, out, it, tag, aclass); 107e1051a39Sopenharmony_ci 108e1051a39Sopenharmony_ci case ASN1_ITYPE_MSTRING: 109e1051a39Sopenharmony_ci /* 110e1051a39Sopenharmony_ci * It never makes sense for multi-strings to have implicit tagging, so 111e1051a39Sopenharmony_ci * if tag != -1, then this looks like an error in the template. 112e1051a39Sopenharmony_ci */ 113e1051a39Sopenharmony_ci if (tag != -1) { 114e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_ASN1, ASN1_R_BAD_TEMPLATE); 115e1051a39Sopenharmony_ci return -1; 116e1051a39Sopenharmony_ci } 117e1051a39Sopenharmony_ci return asn1_i2d_ex_primitive(pval, out, it, -1, aclass); 118e1051a39Sopenharmony_ci 119e1051a39Sopenharmony_ci case ASN1_ITYPE_CHOICE: 120e1051a39Sopenharmony_ci /* 121e1051a39Sopenharmony_ci * It never makes sense for CHOICE types to have implicit tagging, so 122e1051a39Sopenharmony_ci * if tag != -1, then this looks like an error in the template. 123e1051a39Sopenharmony_ci */ 124e1051a39Sopenharmony_ci if (tag != -1) { 125e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_ASN1, ASN1_R_BAD_TEMPLATE); 126e1051a39Sopenharmony_ci return -1; 127e1051a39Sopenharmony_ci } 128e1051a39Sopenharmony_ci if (asn1_cb && !asn1_cb(ASN1_OP_I2D_PRE, pval, it, NULL)) 129e1051a39Sopenharmony_ci return 0; 130e1051a39Sopenharmony_ci i = ossl_asn1_get_choice_selector_const(pval, it); 131e1051a39Sopenharmony_ci if ((i >= 0) && (i < it->tcount)) { 132e1051a39Sopenharmony_ci const ASN1_VALUE **pchval; 133e1051a39Sopenharmony_ci const ASN1_TEMPLATE *chtt; 134e1051a39Sopenharmony_ci chtt = it->templates + i; 135e1051a39Sopenharmony_ci pchval = ossl_asn1_get_const_field_ptr(pval, chtt); 136e1051a39Sopenharmony_ci return asn1_template_ex_i2d(pchval, out, chtt, -1, aclass); 137e1051a39Sopenharmony_ci } 138e1051a39Sopenharmony_ci /* Fixme: error condition if selector out of range */ 139e1051a39Sopenharmony_ci if (asn1_cb && !asn1_cb(ASN1_OP_I2D_POST, pval, it, NULL)) 140e1051a39Sopenharmony_ci return 0; 141e1051a39Sopenharmony_ci break; 142e1051a39Sopenharmony_ci 143e1051a39Sopenharmony_ci case ASN1_ITYPE_EXTERN: 144e1051a39Sopenharmony_ci /* If new style i2d it does all the work */ 145e1051a39Sopenharmony_ci ef = it->funcs; 146e1051a39Sopenharmony_ci return ef->asn1_ex_i2d(pval, out, it, tag, aclass); 147e1051a39Sopenharmony_ci 148e1051a39Sopenharmony_ci case ASN1_ITYPE_NDEF_SEQUENCE: 149e1051a39Sopenharmony_ci /* Use indefinite length constructed if requested */ 150e1051a39Sopenharmony_ci if (aclass & ASN1_TFLG_NDEF) 151e1051a39Sopenharmony_ci ndef = 2; 152e1051a39Sopenharmony_ci /* fall through */ 153e1051a39Sopenharmony_ci 154e1051a39Sopenharmony_ci case ASN1_ITYPE_SEQUENCE: 155e1051a39Sopenharmony_ci i = ossl_asn1_enc_restore(&seqcontlen, out, pval, it); 156e1051a39Sopenharmony_ci /* An error occurred */ 157e1051a39Sopenharmony_ci if (i < 0) 158e1051a39Sopenharmony_ci return 0; 159e1051a39Sopenharmony_ci /* We have a valid cached encoding... */ 160e1051a39Sopenharmony_ci if (i > 0) 161e1051a39Sopenharmony_ci return seqcontlen; 162e1051a39Sopenharmony_ci /* Otherwise carry on */ 163e1051a39Sopenharmony_ci seqcontlen = 0; 164e1051a39Sopenharmony_ci /* If no IMPLICIT tagging set to SEQUENCE, UNIVERSAL */ 165e1051a39Sopenharmony_ci if (tag == -1) { 166e1051a39Sopenharmony_ci tag = V_ASN1_SEQUENCE; 167e1051a39Sopenharmony_ci /* Retain any other flags in aclass */ 168e1051a39Sopenharmony_ci aclass = (aclass & ~ASN1_TFLG_TAG_CLASS) 169e1051a39Sopenharmony_ci | V_ASN1_UNIVERSAL; 170e1051a39Sopenharmony_ci } 171e1051a39Sopenharmony_ci if (asn1_cb && !asn1_cb(ASN1_OP_I2D_PRE, pval, it, NULL)) 172e1051a39Sopenharmony_ci return 0; 173e1051a39Sopenharmony_ci /* First work out sequence content length */ 174e1051a39Sopenharmony_ci for (i = 0, tt = it->templates; i < it->tcount; tt++, i++) { 175e1051a39Sopenharmony_ci const ASN1_TEMPLATE *seqtt; 176e1051a39Sopenharmony_ci const ASN1_VALUE **pseqval; 177e1051a39Sopenharmony_ci int tmplen; 178e1051a39Sopenharmony_ci seqtt = ossl_asn1_do_adb(*pval, tt, 1); 179e1051a39Sopenharmony_ci if (!seqtt) 180e1051a39Sopenharmony_ci return 0; 181e1051a39Sopenharmony_ci pseqval = ossl_asn1_get_const_field_ptr(pval, seqtt); 182e1051a39Sopenharmony_ci tmplen = asn1_template_ex_i2d(pseqval, NULL, seqtt, -1, aclass); 183e1051a39Sopenharmony_ci if (tmplen == -1 || (tmplen > INT_MAX - seqcontlen)) 184e1051a39Sopenharmony_ci return -1; 185e1051a39Sopenharmony_ci seqcontlen += tmplen; 186e1051a39Sopenharmony_ci } 187e1051a39Sopenharmony_ci 188e1051a39Sopenharmony_ci seqlen = ASN1_object_size(ndef, seqcontlen, tag); 189e1051a39Sopenharmony_ci if (!out || seqlen == -1) 190e1051a39Sopenharmony_ci return seqlen; 191e1051a39Sopenharmony_ci /* Output SEQUENCE header */ 192e1051a39Sopenharmony_ci ASN1_put_object(out, ndef, seqcontlen, tag, aclass); 193e1051a39Sopenharmony_ci for (i = 0, tt = it->templates; i < it->tcount; tt++, i++) { 194e1051a39Sopenharmony_ci const ASN1_TEMPLATE *seqtt; 195e1051a39Sopenharmony_ci const ASN1_VALUE **pseqval; 196e1051a39Sopenharmony_ci seqtt = ossl_asn1_do_adb(*pval, tt, 1); 197e1051a39Sopenharmony_ci if (!seqtt) 198e1051a39Sopenharmony_ci return 0; 199e1051a39Sopenharmony_ci pseqval = ossl_asn1_get_const_field_ptr(pval, seqtt); 200e1051a39Sopenharmony_ci /* FIXME: check for errors in enhanced version */ 201e1051a39Sopenharmony_ci asn1_template_ex_i2d(pseqval, out, seqtt, -1, aclass); 202e1051a39Sopenharmony_ci } 203e1051a39Sopenharmony_ci if (ndef == 2) 204e1051a39Sopenharmony_ci ASN1_put_eoc(out); 205e1051a39Sopenharmony_ci if (asn1_cb && !asn1_cb(ASN1_OP_I2D_POST, pval, it, NULL)) 206e1051a39Sopenharmony_ci return 0; 207e1051a39Sopenharmony_ci return seqlen; 208e1051a39Sopenharmony_ci 209e1051a39Sopenharmony_ci default: 210e1051a39Sopenharmony_ci return 0; 211e1051a39Sopenharmony_ci 212e1051a39Sopenharmony_ci } 213e1051a39Sopenharmony_ci return 0; 214e1051a39Sopenharmony_ci} 215e1051a39Sopenharmony_ci 216e1051a39Sopenharmony_cistatic int asn1_template_ex_i2d(const ASN1_VALUE **pval, unsigned char **out, 217e1051a39Sopenharmony_ci const ASN1_TEMPLATE *tt, int tag, int iclass) 218e1051a39Sopenharmony_ci{ 219e1051a39Sopenharmony_ci const int flags = tt->flags; 220e1051a39Sopenharmony_ci int i, ret, ttag, tclass, ndef, len; 221e1051a39Sopenharmony_ci const ASN1_VALUE *tval; 222e1051a39Sopenharmony_ci 223e1051a39Sopenharmony_ci /* 224e1051a39Sopenharmony_ci * If field is embedded then val needs fixing so it is a pointer to 225e1051a39Sopenharmony_ci * a pointer to a field. 226e1051a39Sopenharmony_ci */ 227e1051a39Sopenharmony_ci if (flags & ASN1_TFLG_EMBED) { 228e1051a39Sopenharmony_ci tval = (ASN1_VALUE *)pval; 229e1051a39Sopenharmony_ci pval = &tval; 230e1051a39Sopenharmony_ci } 231e1051a39Sopenharmony_ci /* 232e1051a39Sopenharmony_ci * Work out tag and class to use: tagging may come either from the 233e1051a39Sopenharmony_ci * template or the arguments, not both because this would create 234e1051a39Sopenharmony_ci * ambiguity. Additionally the iclass argument may contain some 235e1051a39Sopenharmony_ci * additional flags which should be noted and passed down to other 236e1051a39Sopenharmony_ci * levels. 237e1051a39Sopenharmony_ci */ 238e1051a39Sopenharmony_ci if (flags & ASN1_TFLG_TAG_MASK) { 239e1051a39Sopenharmony_ci /* Error if argument and template tagging */ 240e1051a39Sopenharmony_ci if (tag != -1) 241e1051a39Sopenharmony_ci /* FIXME: error code here */ 242e1051a39Sopenharmony_ci return -1; 243e1051a39Sopenharmony_ci /* Get tagging from template */ 244e1051a39Sopenharmony_ci ttag = tt->tag; 245e1051a39Sopenharmony_ci tclass = flags & ASN1_TFLG_TAG_CLASS; 246e1051a39Sopenharmony_ci } else if (tag != -1) { 247e1051a39Sopenharmony_ci /* No template tagging, get from arguments */ 248e1051a39Sopenharmony_ci ttag = tag; 249e1051a39Sopenharmony_ci tclass = iclass & ASN1_TFLG_TAG_CLASS; 250e1051a39Sopenharmony_ci } else { 251e1051a39Sopenharmony_ci ttag = -1; 252e1051a39Sopenharmony_ci tclass = 0; 253e1051a39Sopenharmony_ci } 254e1051a39Sopenharmony_ci /* 255e1051a39Sopenharmony_ci * Remove any class mask from iflag. 256e1051a39Sopenharmony_ci */ 257e1051a39Sopenharmony_ci iclass &= ~ASN1_TFLG_TAG_CLASS; 258e1051a39Sopenharmony_ci 259e1051a39Sopenharmony_ci /* 260e1051a39Sopenharmony_ci * At this point 'ttag' contains the outer tag to use, 'tclass' is the 261e1051a39Sopenharmony_ci * class and iclass is any flags passed to this function. 262e1051a39Sopenharmony_ci */ 263e1051a39Sopenharmony_ci 264e1051a39Sopenharmony_ci /* if template and arguments require ndef, use it */ 265e1051a39Sopenharmony_ci if ((flags & ASN1_TFLG_NDEF) && (iclass & ASN1_TFLG_NDEF)) 266e1051a39Sopenharmony_ci ndef = 2; 267e1051a39Sopenharmony_ci else 268e1051a39Sopenharmony_ci ndef = 1; 269e1051a39Sopenharmony_ci 270e1051a39Sopenharmony_ci if (flags & ASN1_TFLG_SK_MASK) { 271e1051a39Sopenharmony_ci /* SET OF, SEQUENCE OF */ 272e1051a39Sopenharmony_ci STACK_OF(const_ASN1_VALUE) *sk = (STACK_OF(const_ASN1_VALUE) *)*pval; 273e1051a39Sopenharmony_ci int isset, sktag, skaclass; 274e1051a39Sopenharmony_ci int skcontlen, sklen; 275e1051a39Sopenharmony_ci const ASN1_VALUE *skitem; 276e1051a39Sopenharmony_ci 277e1051a39Sopenharmony_ci if (*pval == NULL) 278e1051a39Sopenharmony_ci return 0; 279e1051a39Sopenharmony_ci 280e1051a39Sopenharmony_ci if (flags & ASN1_TFLG_SET_OF) { 281e1051a39Sopenharmony_ci isset = 1; 282e1051a39Sopenharmony_ci /* 2 means we reorder */ 283e1051a39Sopenharmony_ci if (flags & ASN1_TFLG_SEQUENCE_OF) 284e1051a39Sopenharmony_ci isset = 2; 285e1051a39Sopenharmony_ci } else 286e1051a39Sopenharmony_ci isset = 0; 287e1051a39Sopenharmony_ci 288e1051a39Sopenharmony_ci /* 289e1051a39Sopenharmony_ci * Work out inner tag value: if EXPLICIT or no tagging use underlying 290e1051a39Sopenharmony_ci * type. 291e1051a39Sopenharmony_ci */ 292e1051a39Sopenharmony_ci if ((ttag != -1) && !(flags & ASN1_TFLG_EXPTAG)) { 293e1051a39Sopenharmony_ci sktag = ttag; 294e1051a39Sopenharmony_ci skaclass = tclass; 295e1051a39Sopenharmony_ci } else { 296e1051a39Sopenharmony_ci skaclass = V_ASN1_UNIVERSAL; 297e1051a39Sopenharmony_ci if (isset) 298e1051a39Sopenharmony_ci sktag = V_ASN1_SET; 299e1051a39Sopenharmony_ci else 300e1051a39Sopenharmony_ci sktag = V_ASN1_SEQUENCE; 301e1051a39Sopenharmony_ci } 302e1051a39Sopenharmony_ci 303e1051a39Sopenharmony_ci /* Determine total length of items */ 304e1051a39Sopenharmony_ci skcontlen = 0; 305e1051a39Sopenharmony_ci for (i = 0; i < sk_const_ASN1_VALUE_num(sk); i++) { 306e1051a39Sopenharmony_ci skitem = sk_const_ASN1_VALUE_value(sk, i); 307e1051a39Sopenharmony_ci len = ASN1_item_ex_i2d(&skitem, NULL, ASN1_ITEM_ptr(tt->item), 308e1051a39Sopenharmony_ci -1, iclass); 309e1051a39Sopenharmony_ci if (len == -1 || (skcontlen > INT_MAX - len)) 310e1051a39Sopenharmony_ci return -1; 311e1051a39Sopenharmony_ci if (len == 0 && (tt->flags & ASN1_TFLG_OPTIONAL) == 0) { 312e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_ASN1, ASN1_R_ILLEGAL_ZERO_CONTENT); 313e1051a39Sopenharmony_ci return -1; 314e1051a39Sopenharmony_ci } 315e1051a39Sopenharmony_ci skcontlen += len; 316e1051a39Sopenharmony_ci } 317e1051a39Sopenharmony_ci sklen = ASN1_object_size(ndef, skcontlen, sktag); 318e1051a39Sopenharmony_ci if (sklen == -1) 319e1051a39Sopenharmony_ci return -1; 320e1051a39Sopenharmony_ci /* If EXPLICIT need length of surrounding tag */ 321e1051a39Sopenharmony_ci if (flags & ASN1_TFLG_EXPTAG) 322e1051a39Sopenharmony_ci ret = ASN1_object_size(ndef, sklen, ttag); 323e1051a39Sopenharmony_ci else 324e1051a39Sopenharmony_ci ret = sklen; 325e1051a39Sopenharmony_ci 326e1051a39Sopenharmony_ci if (!out || ret == -1) 327e1051a39Sopenharmony_ci return ret; 328e1051a39Sopenharmony_ci 329e1051a39Sopenharmony_ci /* Now encode this lot... */ 330e1051a39Sopenharmony_ci /* EXPLICIT tag */ 331e1051a39Sopenharmony_ci if (flags & ASN1_TFLG_EXPTAG) 332e1051a39Sopenharmony_ci ASN1_put_object(out, ndef, sklen, ttag, tclass); 333e1051a39Sopenharmony_ci /* SET or SEQUENCE and IMPLICIT tag */ 334e1051a39Sopenharmony_ci ASN1_put_object(out, ndef, skcontlen, sktag, skaclass); 335e1051a39Sopenharmony_ci /* And the stuff itself */ 336e1051a39Sopenharmony_ci asn1_set_seq_out(sk, out, skcontlen, ASN1_ITEM_ptr(tt->item), 337e1051a39Sopenharmony_ci isset, iclass); 338e1051a39Sopenharmony_ci if (ndef == 2) { 339e1051a39Sopenharmony_ci ASN1_put_eoc(out); 340e1051a39Sopenharmony_ci if (flags & ASN1_TFLG_EXPTAG) 341e1051a39Sopenharmony_ci ASN1_put_eoc(out); 342e1051a39Sopenharmony_ci } 343e1051a39Sopenharmony_ci 344e1051a39Sopenharmony_ci return ret; 345e1051a39Sopenharmony_ci } 346e1051a39Sopenharmony_ci 347e1051a39Sopenharmony_ci if (flags & ASN1_TFLG_EXPTAG) { 348e1051a39Sopenharmony_ci /* EXPLICIT tagging */ 349e1051a39Sopenharmony_ci /* Find length of tagged item */ 350e1051a39Sopenharmony_ci i = ASN1_item_ex_i2d(pval, NULL, ASN1_ITEM_ptr(tt->item), -1, iclass); 351e1051a39Sopenharmony_ci if (i == 0) { 352e1051a39Sopenharmony_ci if ((tt->flags & ASN1_TFLG_OPTIONAL) == 0) { 353e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_ASN1, ASN1_R_ILLEGAL_ZERO_CONTENT); 354e1051a39Sopenharmony_ci return -1; 355e1051a39Sopenharmony_ci } 356e1051a39Sopenharmony_ci return 0; 357e1051a39Sopenharmony_ci } 358e1051a39Sopenharmony_ci /* Find length of EXPLICIT tag */ 359e1051a39Sopenharmony_ci ret = ASN1_object_size(ndef, i, ttag); 360e1051a39Sopenharmony_ci if (out && ret != -1) { 361e1051a39Sopenharmony_ci /* Output tag and item */ 362e1051a39Sopenharmony_ci ASN1_put_object(out, ndef, i, ttag, tclass); 363e1051a39Sopenharmony_ci ASN1_item_ex_i2d(pval, out, ASN1_ITEM_ptr(tt->item), -1, iclass); 364e1051a39Sopenharmony_ci if (ndef == 2) 365e1051a39Sopenharmony_ci ASN1_put_eoc(out); 366e1051a39Sopenharmony_ci } 367e1051a39Sopenharmony_ci return ret; 368e1051a39Sopenharmony_ci } 369e1051a39Sopenharmony_ci 370e1051a39Sopenharmony_ci /* Either normal or IMPLICIT tagging: combine class and flags */ 371e1051a39Sopenharmony_ci len = ASN1_item_ex_i2d(pval, out, ASN1_ITEM_ptr(tt->item), 372e1051a39Sopenharmony_ci ttag, tclass | iclass); 373e1051a39Sopenharmony_ci if (len == 0 && (tt->flags & ASN1_TFLG_OPTIONAL) == 0) { 374e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_ASN1, ASN1_R_ILLEGAL_ZERO_CONTENT); 375e1051a39Sopenharmony_ci return -1; 376e1051a39Sopenharmony_ci } 377e1051a39Sopenharmony_ci return len; 378e1051a39Sopenharmony_ci} 379e1051a39Sopenharmony_ci 380e1051a39Sopenharmony_ci/* Temporary structure used to hold DER encoding of items for SET OF */ 381e1051a39Sopenharmony_ci 382e1051a39Sopenharmony_citypedef struct { 383e1051a39Sopenharmony_ci unsigned char *data; 384e1051a39Sopenharmony_ci int length; 385e1051a39Sopenharmony_ci const ASN1_VALUE *field; 386e1051a39Sopenharmony_ci} DER_ENC; 387e1051a39Sopenharmony_ci 388e1051a39Sopenharmony_cistatic int der_cmp(const void *a, const void *b) 389e1051a39Sopenharmony_ci{ 390e1051a39Sopenharmony_ci const DER_ENC *d1 = a, *d2 = b; 391e1051a39Sopenharmony_ci int cmplen, i; 392e1051a39Sopenharmony_ci cmplen = (d1->length < d2->length) ? d1->length : d2->length; 393e1051a39Sopenharmony_ci i = memcmp(d1->data, d2->data, cmplen); 394e1051a39Sopenharmony_ci if (i) 395e1051a39Sopenharmony_ci return i; 396e1051a39Sopenharmony_ci return d1->length - d2->length; 397e1051a39Sopenharmony_ci} 398e1051a39Sopenharmony_ci 399e1051a39Sopenharmony_ci/* Output the content octets of SET OF or SEQUENCE OF */ 400e1051a39Sopenharmony_ci 401e1051a39Sopenharmony_cistatic int asn1_set_seq_out(STACK_OF(const_ASN1_VALUE) *sk, 402e1051a39Sopenharmony_ci unsigned char **out, 403e1051a39Sopenharmony_ci int skcontlen, const ASN1_ITEM *item, 404e1051a39Sopenharmony_ci int do_sort, int iclass) 405e1051a39Sopenharmony_ci{ 406e1051a39Sopenharmony_ci int i, ret = 0; 407e1051a39Sopenharmony_ci const ASN1_VALUE *skitem; 408e1051a39Sopenharmony_ci unsigned char *tmpdat = NULL, *p = NULL; 409e1051a39Sopenharmony_ci DER_ENC *derlst = NULL, *tder; 410e1051a39Sopenharmony_ci 411e1051a39Sopenharmony_ci if (do_sort) { 412e1051a39Sopenharmony_ci /* Don't need to sort less than 2 items */ 413e1051a39Sopenharmony_ci if (sk_const_ASN1_VALUE_num(sk) < 2) 414e1051a39Sopenharmony_ci do_sort = 0; 415e1051a39Sopenharmony_ci else { 416e1051a39Sopenharmony_ci derlst = OPENSSL_malloc(sk_const_ASN1_VALUE_num(sk) 417e1051a39Sopenharmony_ci * sizeof(*derlst)); 418e1051a39Sopenharmony_ci if (derlst == NULL) { 419e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE); 420e1051a39Sopenharmony_ci return 0; 421e1051a39Sopenharmony_ci } 422e1051a39Sopenharmony_ci tmpdat = OPENSSL_malloc(skcontlen); 423e1051a39Sopenharmony_ci if (tmpdat == NULL) { 424e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE); 425e1051a39Sopenharmony_ci goto err; 426e1051a39Sopenharmony_ci } 427e1051a39Sopenharmony_ci } 428e1051a39Sopenharmony_ci } 429e1051a39Sopenharmony_ci /* If not sorting just output each item */ 430e1051a39Sopenharmony_ci if (!do_sort) { 431e1051a39Sopenharmony_ci for (i = 0; i < sk_const_ASN1_VALUE_num(sk); i++) { 432e1051a39Sopenharmony_ci skitem = sk_const_ASN1_VALUE_value(sk, i); 433e1051a39Sopenharmony_ci ASN1_item_ex_i2d(&skitem, out, item, -1, iclass); 434e1051a39Sopenharmony_ci } 435e1051a39Sopenharmony_ci return 1; 436e1051a39Sopenharmony_ci } 437e1051a39Sopenharmony_ci p = tmpdat; 438e1051a39Sopenharmony_ci 439e1051a39Sopenharmony_ci /* Doing sort: build up a list of each member's DER encoding */ 440e1051a39Sopenharmony_ci for (i = 0, tder = derlst; i < sk_const_ASN1_VALUE_num(sk); i++, tder++) { 441e1051a39Sopenharmony_ci skitem = sk_const_ASN1_VALUE_value(sk, i); 442e1051a39Sopenharmony_ci tder->data = p; 443e1051a39Sopenharmony_ci tder->length = ASN1_item_ex_i2d(&skitem, &p, item, -1, iclass); 444e1051a39Sopenharmony_ci tder->field = skitem; 445e1051a39Sopenharmony_ci } 446e1051a39Sopenharmony_ci 447e1051a39Sopenharmony_ci /* Now sort them */ 448e1051a39Sopenharmony_ci qsort(derlst, sk_const_ASN1_VALUE_num(sk), sizeof(*derlst), der_cmp); 449e1051a39Sopenharmony_ci /* Output sorted DER encoding */ 450e1051a39Sopenharmony_ci p = *out; 451e1051a39Sopenharmony_ci for (i = 0, tder = derlst; i < sk_const_ASN1_VALUE_num(sk); i++, tder++) { 452e1051a39Sopenharmony_ci memcpy(p, tder->data, tder->length); 453e1051a39Sopenharmony_ci p += tder->length; 454e1051a39Sopenharmony_ci } 455e1051a39Sopenharmony_ci *out = p; 456e1051a39Sopenharmony_ci /* If do_sort is 2 then reorder the STACK */ 457e1051a39Sopenharmony_ci if (do_sort == 2) { 458e1051a39Sopenharmony_ci for (i = 0, tder = derlst; i < sk_const_ASN1_VALUE_num(sk); i++, tder++) 459e1051a39Sopenharmony_ci (void)sk_const_ASN1_VALUE_set(sk, i, tder->field); 460e1051a39Sopenharmony_ci } 461e1051a39Sopenharmony_ci ret = 1; 462e1051a39Sopenharmony_cierr: 463e1051a39Sopenharmony_ci OPENSSL_free(derlst); 464e1051a39Sopenharmony_ci OPENSSL_free(tmpdat); 465e1051a39Sopenharmony_ci return ret; 466e1051a39Sopenharmony_ci} 467e1051a39Sopenharmony_ci 468e1051a39Sopenharmony_cistatic int asn1_i2d_ex_primitive(const ASN1_VALUE **pval, unsigned char **out, 469e1051a39Sopenharmony_ci const ASN1_ITEM *it, int tag, int aclass) 470e1051a39Sopenharmony_ci{ 471e1051a39Sopenharmony_ci int len; 472e1051a39Sopenharmony_ci int utype; 473e1051a39Sopenharmony_ci int usetag; 474e1051a39Sopenharmony_ci int ndef = 0; 475e1051a39Sopenharmony_ci 476e1051a39Sopenharmony_ci utype = it->utype; 477e1051a39Sopenharmony_ci 478e1051a39Sopenharmony_ci /* 479e1051a39Sopenharmony_ci * Get length of content octets and maybe find out the underlying type. 480e1051a39Sopenharmony_ci */ 481e1051a39Sopenharmony_ci 482e1051a39Sopenharmony_ci len = asn1_ex_i2c(pval, NULL, &utype, it); 483e1051a39Sopenharmony_ci 484e1051a39Sopenharmony_ci /* 485e1051a39Sopenharmony_ci * If SEQUENCE, SET or OTHER then header is included in pseudo content 486e1051a39Sopenharmony_ci * octets so don't include tag+length. We need to check here because the 487e1051a39Sopenharmony_ci * call to asn1_ex_i2c() could change utype. 488e1051a39Sopenharmony_ci */ 489e1051a39Sopenharmony_ci if ((utype == V_ASN1_SEQUENCE) || (utype == V_ASN1_SET) || 490e1051a39Sopenharmony_ci (utype == V_ASN1_OTHER)) 491e1051a39Sopenharmony_ci usetag = 0; 492e1051a39Sopenharmony_ci else 493e1051a39Sopenharmony_ci usetag = 1; 494e1051a39Sopenharmony_ci 495e1051a39Sopenharmony_ci /* -1 means omit type */ 496e1051a39Sopenharmony_ci 497e1051a39Sopenharmony_ci if (len == -1) 498e1051a39Sopenharmony_ci return 0; 499e1051a39Sopenharmony_ci 500e1051a39Sopenharmony_ci /* -2 return is special meaning use ndef */ 501e1051a39Sopenharmony_ci if (len == -2) { 502e1051a39Sopenharmony_ci ndef = 2; 503e1051a39Sopenharmony_ci len = 0; 504e1051a39Sopenharmony_ci } 505e1051a39Sopenharmony_ci 506e1051a39Sopenharmony_ci /* If not implicitly tagged get tag from underlying type */ 507e1051a39Sopenharmony_ci if (tag == -1) 508e1051a39Sopenharmony_ci tag = utype; 509e1051a39Sopenharmony_ci 510e1051a39Sopenharmony_ci /* Output tag+length followed by content octets */ 511e1051a39Sopenharmony_ci if (out) { 512e1051a39Sopenharmony_ci if (usetag) 513e1051a39Sopenharmony_ci ASN1_put_object(out, ndef, len, tag, aclass); 514e1051a39Sopenharmony_ci asn1_ex_i2c(pval, *out, &utype, it); 515e1051a39Sopenharmony_ci if (ndef) 516e1051a39Sopenharmony_ci ASN1_put_eoc(out); 517e1051a39Sopenharmony_ci else 518e1051a39Sopenharmony_ci *out += len; 519e1051a39Sopenharmony_ci } 520e1051a39Sopenharmony_ci 521e1051a39Sopenharmony_ci if (usetag) 522e1051a39Sopenharmony_ci return ASN1_object_size(ndef, len, tag); 523e1051a39Sopenharmony_ci return len; 524e1051a39Sopenharmony_ci} 525e1051a39Sopenharmony_ci 526e1051a39Sopenharmony_ci/* Produce content octets from a structure */ 527e1051a39Sopenharmony_ci 528e1051a39Sopenharmony_cistatic int asn1_ex_i2c(const ASN1_VALUE **pval, unsigned char *cout, int *putype, 529e1051a39Sopenharmony_ci const ASN1_ITEM *it) 530e1051a39Sopenharmony_ci{ 531e1051a39Sopenharmony_ci ASN1_BOOLEAN *tbool = NULL; 532e1051a39Sopenharmony_ci ASN1_STRING *strtmp; 533e1051a39Sopenharmony_ci ASN1_OBJECT *otmp; 534e1051a39Sopenharmony_ci int utype; 535e1051a39Sopenharmony_ci const unsigned char *cont; 536e1051a39Sopenharmony_ci unsigned char c; 537e1051a39Sopenharmony_ci int len; 538e1051a39Sopenharmony_ci const ASN1_PRIMITIVE_FUNCS *pf; 539e1051a39Sopenharmony_ci pf = it->funcs; 540e1051a39Sopenharmony_ci if (pf && pf->prim_i2c) 541e1051a39Sopenharmony_ci return pf->prim_i2c(pval, cout, putype, it); 542e1051a39Sopenharmony_ci 543e1051a39Sopenharmony_ci /* Should type be omitted? */ 544e1051a39Sopenharmony_ci if ((it->itype != ASN1_ITYPE_PRIMITIVE) 545e1051a39Sopenharmony_ci || (it->utype != V_ASN1_BOOLEAN)) { 546e1051a39Sopenharmony_ci if (*pval == NULL) 547e1051a39Sopenharmony_ci return -1; 548e1051a39Sopenharmony_ci } 549e1051a39Sopenharmony_ci 550e1051a39Sopenharmony_ci if (it->itype == ASN1_ITYPE_MSTRING) { 551e1051a39Sopenharmony_ci /* If MSTRING type set the underlying type */ 552e1051a39Sopenharmony_ci strtmp = (ASN1_STRING *)*pval; 553e1051a39Sopenharmony_ci utype = strtmp->type; 554e1051a39Sopenharmony_ci *putype = utype; 555e1051a39Sopenharmony_ci } else if (it->utype == V_ASN1_ANY) { 556e1051a39Sopenharmony_ci /* If ANY set type and pointer to value */ 557e1051a39Sopenharmony_ci ASN1_TYPE *typ; 558e1051a39Sopenharmony_ci typ = (ASN1_TYPE *)*pval; 559e1051a39Sopenharmony_ci utype = typ->type; 560e1051a39Sopenharmony_ci *putype = utype; 561e1051a39Sopenharmony_ci pval = (const ASN1_VALUE **)&typ->value.asn1_value; /* actually is const */ 562e1051a39Sopenharmony_ci } else 563e1051a39Sopenharmony_ci utype = *putype; 564e1051a39Sopenharmony_ci 565e1051a39Sopenharmony_ci switch (utype) { 566e1051a39Sopenharmony_ci case V_ASN1_OBJECT: 567e1051a39Sopenharmony_ci otmp = (ASN1_OBJECT *)*pval; 568e1051a39Sopenharmony_ci cont = otmp->data; 569e1051a39Sopenharmony_ci len = otmp->length; 570e1051a39Sopenharmony_ci if (cont == NULL || len == 0) 571e1051a39Sopenharmony_ci return -1; 572e1051a39Sopenharmony_ci break; 573e1051a39Sopenharmony_ci 574e1051a39Sopenharmony_ci case V_ASN1_NULL: 575e1051a39Sopenharmony_ci cont = NULL; 576e1051a39Sopenharmony_ci len = 0; 577e1051a39Sopenharmony_ci break; 578e1051a39Sopenharmony_ci 579e1051a39Sopenharmony_ci case V_ASN1_BOOLEAN: 580e1051a39Sopenharmony_ci tbool = (ASN1_BOOLEAN *)pval; 581e1051a39Sopenharmony_ci if (*tbool == -1) 582e1051a39Sopenharmony_ci return -1; 583e1051a39Sopenharmony_ci if (it->utype != V_ASN1_ANY) { 584e1051a39Sopenharmony_ci /* 585e1051a39Sopenharmony_ci * Default handling if value == size field then omit 586e1051a39Sopenharmony_ci */ 587e1051a39Sopenharmony_ci if (*tbool && (it->size > 0)) 588e1051a39Sopenharmony_ci return -1; 589e1051a39Sopenharmony_ci if (!*tbool && !it->size) 590e1051a39Sopenharmony_ci return -1; 591e1051a39Sopenharmony_ci } 592e1051a39Sopenharmony_ci c = (unsigned char)*tbool; 593e1051a39Sopenharmony_ci cont = &c; 594e1051a39Sopenharmony_ci len = 1; 595e1051a39Sopenharmony_ci break; 596e1051a39Sopenharmony_ci 597e1051a39Sopenharmony_ci case V_ASN1_BIT_STRING: 598e1051a39Sopenharmony_ci return ossl_i2c_ASN1_BIT_STRING((ASN1_BIT_STRING *)*pval, 599e1051a39Sopenharmony_ci cout ? &cout : NULL); 600e1051a39Sopenharmony_ci 601e1051a39Sopenharmony_ci case V_ASN1_INTEGER: 602e1051a39Sopenharmony_ci case V_ASN1_ENUMERATED: 603e1051a39Sopenharmony_ci /* 604e1051a39Sopenharmony_ci * These are all have the same content format as ASN1_INTEGER 605e1051a39Sopenharmony_ci */ 606e1051a39Sopenharmony_ci return ossl_i2c_ASN1_INTEGER((ASN1_INTEGER *)*pval, cout ? &cout : NULL); 607e1051a39Sopenharmony_ci 608e1051a39Sopenharmony_ci case V_ASN1_OCTET_STRING: 609e1051a39Sopenharmony_ci case V_ASN1_NUMERICSTRING: 610e1051a39Sopenharmony_ci case V_ASN1_PRINTABLESTRING: 611e1051a39Sopenharmony_ci case V_ASN1_T61STRING: 612e1051a39Sopenharmony_ci case V_ASN1_VIDEOTEXSTRING: 613e1051a39Sopenharmony_ci case V_ASN1_IA5STRING: 614e1051a39Sopenharmony_ci case V_ASN1_UTCTIME: 615e1051a39Sopenharmony_ci case V_ASN1_GENERALIZEDTIME: 616e1051a39Sopenharmony_ci case V_ASN1_GRAPHICSTRING: 617e1051a39Sopenharmony_ci case V_ASN1_VISIBLESTRING: 618e1051a39Sopenharmony_ci case V_ASN1_GENERALSTRING: 619e1051a39Sopenharmony_ci case V_ASN1_UNIVERSALSTRING: 620e1051a39Sopenharmony_ci case V_ASN1_BMPSTRING: 621e1051a39Sopenharmony_ci case V_ASN1_UTF8STRING: 622e1051a39Sopenharmony_ci case V_ASN1_SEQUENCE: 623e1051a39Sopenharmony_ci case V_ASN1_SET: 624e1051a39Sopenharmony_ci default: 625e1051a39Sopenharmony_ci /* All based on ASN1_STRING and handled the same */ 626e1051a39Sopenharmony_ci strtmp = (ASN1_STRING *)*pval; 627e1051a39Sopenharmony_ci /* Special handling for NDEF */ 628e1051a39Sopenharmony_ci if ((it->size == ASN1_TFLG_NDEF) 629e1051a39Sopenharmony_ci && (strtmp->flags & ASN1_STRING_FLAG_NDEF)) { 630e1051a39Sopenharmony_ci if (cout) { 631e1051a39Sopenharmony_ci strtmp->data = cout; 632e1051a39Sopenharmony_ci strtmp->length = 0; 633e1051a39Sopenharmony_ci } 634e1051a39Sopenharmony_ci /* Special return code */ 635e1051a39Sopenharmony_ci return -2; 636e1051a39Sopenharmony_ci } 637e1051a39Sopenharmony_ci cont = strtmp->data; 638e1051a39Sopenharmony_ci len = strtmp->length; 639e1051a39Sopenharmony_ci 640e1051a39Sopenharmony_ci break; 641e1051a39Sopenharmony_ci 642e1051a39Sopenharmony_ci } 643e1051a39Sopenharmony_ci if (cout && len) 644e1051a39Sopenharmony_ci memcpy(cout, cont, len); 645e1051a39Sopenharmony_ci return len; 646e1051a39Sopenharmony_ci} 647