Embed:
(wiki syntax)
Show/hide line numbers
asn1.c
Go to the documentation of this file.
00001 /** 00002 * @file asn1.c 00003 * @brief ASN.1 (Abstract Syntax Notation One) 00004 * 00005 * @section License 00006 * 00007 * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved. 00008 * 00009 * This file is part of CycloneCrypto Open. 00010 * 00011 * This program is free software; you can redistribute it and/or 00012 * modify it under the terms of the GNU General Public License 00013 * as published by the Free Software Foundation; either version 2 00014 * of the License, or (at your option) any later version. 00015 * 00016 * This program is distributed in the hope that it will be useful, 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00019 * GNU General Public License for more details. 00020 * 00021 * You should have received a copy of the GNU General Public License 00022 * along with this program; if not, write to the Free Software Foundation, 00023 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00024 * 00025 * @author Oryx Embedded SARL (www.oryx-embedded.com) 00026 * @version 1.7.6 00027 **/ 00028 00029 //Switch to the appropriate trace level 00030 #define TRACE_LEVEL CRYPTO_TRACE_LEVEL 00031 00032 //Dependencies 00033 #include <string.h> 00034 #include "crypto.h" 00035 #include "asn1.h" 00036 #include "oid.h" 00037 #include "debug.h" 00038 00039 //Check crypto library configuration 00040 #if (ASN1_SUPPORT == ENABLED) 00041 00042 00043 /** 00044 * @brief Read an ASN.1 tag from the input stream 00045 * @param[in] data Input stream where to read the tag 00046 * @param[in] length Number of bytes available in the input stream 00047 * @param[out] tag Structure describing the ASN.1 tag 00048 * @return Error code 00049 **/ 00050 00051 error_t asn1ReadTag(const uint8_t *data, size_t length, Asn1Tag *tag) 00052 { 00053 uint_t i; 00054 uint_t n; 00055 00056 //Make sure the identifier octet is present 00057 if(!length) 00058 return ERROR_INVALID_TAG; 00059 00060 //Save the class of the ASN.1 tag 00061 tag->objClass = data[0] & ASN1_CLASS_MASK; 00062 //Primitive or constructed encoding? 00063 tag->constructed = (data[0] & ASN1_ENCODING_CONSTRUCTED) ? TRUE : FALSE; 00064 00065 //Check the tag number 00066 if((data[0] & ASN1_TAG_NUMBER_MASK) < 31) 00067 { 00068 //Tag number is in the range 0 to 30 00069 tag->objType = data[0] & ASN1_TAG_NUMBER_MASK; 00070 //Point to the tag length field 00071 i = 1; 00072 } 00073 else 00074 { 00075 //If the tag number is greater than or equal to 31, 00076 //the subsequent octets will encode the tag number 00077 tag->objType = 0; 00078 00079 //Decode the tag number 00080 for(i = 1; ; i++) 00081 { 00082 //The field cannot exceed 5 bytes 00083 if(i > (sizeof(tag->objType) + 1)) 00084 return ERROR_INVALID_TAG; 00085 //Insufficient number of bytes to decode the tag number? 00086 if(!(length - i)) 00087 return ERROR_INVALID_TAG; 00088 00089 //Update the tag number with bits 7 to 1 00090 tag->objType = (tag->objType << 7) | (data[i] & 0x7F); 00091 00092 //Bit 8 shall be set unless it is the last octet 00093 if(!(data[i] & 0x80)) 00094 break; 00095 } 00096 //Point to the tag length field 00097 i++; 00098 } 00099 00100 //Insufficient number of bytes to decode the tag length? 00101 if(!(length - i)) 00102 return ERROR_INVALID_TAG; 00103 00104 //Short form is used? 00105 if(data[i] < 128) 00106 { 00107 //Bits 7 to 1 encode the number of bytes in the contents 00108 tag->length = data[i]; 00109 //Point to the contents of the tag 00110 i++; 00111 } 00112 //Long form is used? 00113 else if(data[i] > 128 && data[i] < 255) 00114 { 00115 //Bits 7 to 1 encode the number of octets in the length field 00116 n = data[i] & 0x7F; 00117 00118 //The field cannot exceed 4 bytes 00119 if(n > sizeof(tag->length)) 00120 return ERROR_INVALID_TAG; 00121 //Insufficient number of bytes to decode the tag length? 00122 if((length - i) < n) 00123 return ERROR_INVALID_TAG; 00124 00125 //Clear the tag length 00126 tag->length = 0; 00127 //Read the subsequent octets 00128 for(i++; n > 0; n--) 00129 tag->length = (tag->length << 8) | data[i++]; 00130 } 00131 //Indefinite form is used? 00132 else 00133 { 00134 //Indefinite form is not supported 00135 return ERROR_INVALID_TAG; 00136 } 00137 00138 //Save the pointer to the tag contents 00139 tag->value = data + i; 00140 //Check the length of tag 00141 if((length - i) < tag->length) 00142 return ERROR_INVALID_TAG; 00143 00144 //Total length occupied by the ASN.1 tag in the input stream 00145 tag->totalLength = i + tag->length; 00146 //ASN.1 tag successfully decoded 00147 return NO_ERROR; 00148 } 00149 00150 00151 /** 00152 * @brief Read an integer from the input stream 00153 * @param[in] data Input stream where to read the tag 00154 * @param[in] length Number of bytes available in the input stream 00155 * @param[out] tag Structure describing the ASN.1 tag 00156 * @param[out] value Integer value 00157 * @return Error code 00158 **/ 00159 00160 error_t asn1ReadInt32(const uint8_t *data, size_t length, Asn1Tag *tag, int32_t *value) 00161 { 00162 error_t error; 00163 size_t i; 00164 00165 //Read ASN.1 tag 00166 error = asn1ReadTag(data, length, tag); 00167 //Failed to decode ASN.1 tag? 00168 if(error) 00169 return error; 00170 00171 //Enforce encoding, class and type 00172 error = asn1CheckTag(tag, FALSE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_INTEGER); 00173 //The tag does not match the criteria? 00174 if(error) 00175 return error; 00176 00177 //The contents shall consist of one or more octets 00178 if(tag->length < 1 || tag->length > 4) 00179 return ERROR_INVALID_TAG; 00180 00181 //The contents octets shall be a two's complement binary 00182 //number equal to the integer value 00183 *value = (tag->value[0] & 0x80) ? -1 : 0; 00184 00185 //Process contents octets 00186 for(i = 0; i < tag->length; i++) 00187 { 00188 //Rotate left operation 00189 *value <<= 8; 00190 //Reconstruct integer value 00191 *value |= tag->value[i]; 00192 } 00193 00194 //ASN.1 tag successfully decoded 00195 return NO_ERROR; 00196 } 00197 00198 00199 /** 00200 * @brief Write an ASN.1 tag 00201 * @param[in] tag Structure describing the ASN.1 tag 00202 * @param[in] reverse Use reverse encoding 00203 * @param[out] data Output stream where to write the tag (optional parameter) 00204 * @param[out] written Number of bytes written to the output stream (optional parameter) 00205 * @return Error code 00206 **/ 00207 00208 error_t asn1WriteTag(Asn1Tag *tag, bool_t reverse, uint8_t *data, size_t *written) 00209 { 00210 size_t i; 00211 size_t m; 00212 size_t n; 00213 00214 //Compute the number of octets that are necessary to encode the tag number 00215 if(tag->objType < 31) 00216 m = 0; 00217 else if(tag->objType < 128) 00218 m = 1; 00219 else if(tag->objType < 16384) 00220 m = 2; 00221 else if(tag->objType < 2097152) 00222 m = 3; 00223 else if(tag->objType < 268435456) 00224 m = 4; 00225 else 00226 m = 5; 00227 00228 //Compute the number of octets that are necessary to encode the length field 00229 if(tag->length < 128) 00230 n = 0; 00231 else if(tag->length < 256) 00232 n = 1; 00233 else if(tag->length < 65536) 00234 n = 2; 00235 else if(tag->length < 16777216) 00236 n = 3; 00237 else 00238 n = 4; 00239 00240 //Valid output stream? 00241 if(data != NULL) 00242 { 00243 //Use reverse encoding? 00244 if(reverse) 00245 { 00246 //Any data to copy? 00247 if(tag->value != NULL && tag->length > 0) 00248 { 00249 //Make room for the data 00250 data -= tag->length; 00251 //Copy data 00252 memmove(data, tag->value, tag->length); 00253 } 00254 00255 //Move backward 00256 data -= m + n + 2; 00257 } 00258 else 00259 { 00260 //Any data to copy? 00261 if(tag->value != NULL && tag->length > 0) 00262 { 00263 //Copy data 00264 memmove(data + m + n + 2, tag->value, tag->length); 00265 } 00266 } 00267 00268 //Save the class of the ASN.1 tag 00269 data[0] = tag->objClass; 00270 00271 //Primitive or constructed encoding? 00272 if(tag->constructed) 00273 data[0] |= ASN1_ENCODING_CONSTRUCTED; 00274 00275 //Encode the tag number 00276 if(m == 0) 00277 { 00278 //Tag number is in the range 0 to 30 00279 data[0] |= tag->objType; 00280 } 00281 else 00282 { 00283 //The tag number is greater than or equal to 31 00284 data[0] |= ASN1_TAG_NUMBER_MASK; 00285 00286 //The subsequent octets will encode the tag number 00287 for(i = 0; i < m; i++) 00288 { 00289 //Bits 7 to 1 encode the tag number 00290 data[m - i] = (tag->objType >> (i * 7)) & 0x7F; 00291 00292 //Bit 8 of each octet shall be set to one unless it is the 00293 //last octet of the identifier octets 00294 if(i != 0) 00295 data[m - i] |= 0x80; 00296 } 00297 } 00298 00299 //Encode the length field 00300 if(n == 0) 00301 { 00302 //Use short form encoding 00303 data[1 + m] = tag->length & 0x7F; 00304 } 00305 else 00306 { 00307 //Bits 7 to 1 encode the number of octets in the length field 00308 data[1 + m] = 0x80 | (n & 0x7F); 00309 00310 //The subsequent octets will encode the length field 00311 for(i = 0; i < n; i++) 00312 { 00313 data[1 + m + n - i] = (tag->length >> (i * 8)) & 0xFF; 00314 } 00315 } 00316 } 00317 00318 //Total length occupied by the ASN.1 tag 00319 tag->totalLength = tag->length + m + n + 2; 00320 00321 //The last parameter is optional 00322 if(written != NULL) 00323 { 00324 //Number of bytes written to the output stream 00325 *written = m + n + 2; 00326 00327 //Any data copied? 00328 if(tag->value != NULL) 00329 *written += tag->length; 00330 } 00331 00332 //Successful processing 00333 return NO_ERROR; 00334 } 00335 00336 00337 /** 00338 * @brief Write an integer to the output stream 00339 * @param[in] value Integer value 00340 * @param[in] reverse Use reverse encoding 00341 * @param[out] data Output stream where to write the tag (optional parameter) 00342 * @param[out] written Number of bytes written to the output stream 00343 * @return Error code 00344 **/ 00345 00346 error_t asn1WriteInt32(int32_t value, bool_t reverse, uint8_t *data, size_t *written) 00347 { 00348 size_t i; 00349 size_t n; 00350 uint16_t msb; 00351 00352 //An integer value is always encoded in the smallest possible number of octets 00353 for(n = 4; n > 1; n--) 00354 { 00355 //Retrieve the upper 9 bits 00356 msb = (value >> (n * 8 - 9)) & 0x01FF; 00357 00358 //The upper 9 bits shall not have the same value (all 0 or all 1) 00359 if(msb != 0x0000 && msb != 0x01FF) 00360 break; 00361 } 00362 00363 //Valid output stream? 00364 if(data != NULL) 00365 { 00366 //Use reverse encoding? 00367 if(reverse) 00368 data -= n + 2; 00369 00370 //Write tag type 00371 data[0] = ASN1_CLASS_UNIVERSAL | ASN1_TYPE_INTEGER; 00372 //Write tag length 00373 data[1] = n & 0xFF; 00374 00375 //Write contents octets 00376 for(i = 0; i < n; i++) 00377 { 00378 data[1 + n - i] = (value >> (i * 8)) & 0xFF; 00379 } 00380 } 00381 00382 //Number of bytes written to the output stream 00383 if(written != NULL) 00384 *written = n + 2; 00385 00386 //Successful processing 00387 return NO_ERROR; 00388 } 00389 00390 00391 /** 00392 * @brief Enforce the type of a specified tag 00393 * @param[in] tag Pointer to an ASN.1 tag 00394 * @param[in] constructed Expected encoding (TRUE for constructed, FALSE for primitive) 00395 * @param[in] objClass Expected tag class 00396 * @param[in] objType Expected tag type 00397 * @return Error code 00398 **/ 00399 00400 error_t asn1CheckTag(const Asn1Tag *tag, bool_t constructed, uint_t objClass, uint_t objType) 00401 { 00402 //Check encoding 00403 if(tag->constructed != constructed) 00404 return ERROR_WRONG_ENCODING; 00405 //Enforce class 00406 if(tag->objClass != objClass) 00407 return ERROR_INVALID_CLASS; 00408 //Enforce type 00409 if(tag->objType != objType) 00410 return ERROR_INVALID_TYPE; 00411 00412 //The tag matches all the criteria 00413 return NO_ERROR; 00414 } 00415 00416 00417 /** 00418 * @brief Check ASN.1 tag against a specified OID 00419 * @param[in] tag Pointer to an ASN.1 tag 00420 * @param[in] oid Expected object identifier (OID) 00421 * @param[in] length Length of the OID 00422 * @return Error code 00423 **/ 00424 00425 error_t asn1CheckOid(const Asn1Tag *tag, const uint8_t *oid, size_t length) 00426 { 00427 error_t error; 00428 00429 //Enforce encoding, class and type 00430 error = asn1CheckTag(tag, FALSE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_OBJECT_IDENTIFIER); 00431 //Any error to report? 00432 if(error) 00433 return error; 00434 00435 //Compare OID against the specified value 00436 if(oidComp(tag->value, tag->length, oid, length)) 00437 return ERROR_WRONG_IDENTIFIER; 00438 00439 //The tag matches all the criteria 00440 return NO_ERROR; 00441 } 00442 00443 00444 /** 00445 * @brief Display an ASN.1 data object 00446 * @param[in] data Pointer to the ASN.1 object to dump 00447 * @param[in] length Length of the ASN.1 object 00448 * @param[in] level Current level of recursion (this parameter shall be set to 0) 00449 * @return Error code 00450 **/ 00451 00452 error_t asn1DumpObject(const uint8_t *data, size_t length, uint_t level) 00453 { 00454 //Check debugging level 00455 #if (TRACE_LEVEL >= TRACE_LEVEL_DEBUG) 00456 error_t error; 00457 uint_t i; 00458 Asn1Tag tag; 00459 00460 //ASN.1 universal types 00461 static const char_t *label[32] = 00462 { 00463 "[0]", 00464 "BOOLEAN", 00465 "INTEGER", 00466 "BIT STRING", 00467 "OCTET STRING", 00468 "NULL", 00469 "OBJECT IDENTIFIER", 00470 "OBJECT DESCRIPTOR", 00471 "EXTERNAL", 00472 "REAL", 00473 "ENUMERATED", 00474 "[11]", 00475 "UTF8 STRING", 00476 "[13]", 00477 "[14]", 00478 "[15]", 00479 "SEQUENCE", 00480 "SET", 00481 "NUMERIC STRING", 00482 "PRINTABLE STRING", 00483 "TELETEX STRING", 00484 "VIDEOTEX STRING", 00485 "IA5 STRING", 00486 "UTC TIME", 00487 "GENERALIZED TIME", 00488 "GRAPHIC STRING", 00489 "VISIBLE STRING", 00490 "GENERAL STRING", 00491 "UNIVERSAL STRING", 00492 "[29]", 00493 "BMP STRING", 00494 "[31]" 00495 }; 00496 00497 //Prefix used to format the structure 00498 static const char_t *prefix[8] = 00499 { 00500 "", 00501 " ", 00502 " ", 00503 " ", 00504 " ", 00505 " ", 00506 " ", 00507 " " 00508 }; 00509 00510 //Parse ASN.1 object 00511 while(length > 0) 00512 { 00513 //Decode current ASN.1 tag 00514 error = asn1ReadTag(data, length, &tag); 00515 //Decoding failed? 00516 if(error) 00517 return error; 00518 00519 //Point to the next field 00520 data += tag.totalLength; 00521 length -= tag.totalLength; 00522 00523 //Dump tag number, tag class, and contents length fields 00524 if(tag.objType < 32 && (tag.objClass & ASN1_CLASS_MASK) == ASN1_CLASS_UNIVERSAL) 00525 TRACE_DEBUG("%s%s (%" PRIuSIZE " bytes)\r\n", prefix[level], label[tag.objType], tag.length); 00526 else 00527 TRACE_DEBUG("%s[%u] (%" PRIuSIZE " bytes)\r\n", prefix[level], tag.objType, tag.length); 00528 00529 //Constructed type? 00530 if(tag.constructed) 00531 { 00532 //Check whether the maximum level of recursion is reached 00533 if(level < 7) 00534 { 00535 //Recursive decoding of the ASN.1 tag 00536 error = asn1DumpObject(tag.value, tag.length, level + 1); 00537 //Decoding failed? 00538 if(error) 00539 return error; 00540 } 00541 else 00542 { 00543 //If the maximum level of recursion is reached, then dump contents 00544 TRACE_DEBUG_ARRAY(prefix[level + 1], tag.value, tag.length); 00545 } 00546 } 00547 //Primitive type? 00548 else 00549 { 00550 //Check the type of the current tag 00551 switch(tag.objType) 00552 { 00553 //OID? 00554 case ASN1_TYPE_OBJECT_IDENTIFIER: 00555 //Append prefix 00556 TRACE_DEBUG(prefix[level + 1]); 00557 //Print OID 00558 TRACE_DEBUG("%s", oidToString(tag.value, tag.length, NULL, 0)); 00559 //Add a line feed 00560 TRACE_DEBUG("\r\n"); 00561 break; 00562 //String? 00563 case ASN1_TYPE_UTF8_STRING: 00564 case ASN1_TYPE_NUMERIC_STRING: 00565 case ASN1_TYPE_PRINTABLE_STRING: 00566 case ASN1_TYPE_TELETEX_STRING: 00567 case ASN1_TYPE_VIDEOTEX_STRING: 00568 case ASN1_TYPE_IA5_STRING: 00569 case ASN1_TYPE_GRAPHIC_STRING: 00570 case ASN1_TYPE_VISIBLE_STRING: 00571 case ASN1_TYPE_GENERAL_STRING: 00572 case ASN1_TYPE_UNIVERSAL_STRING: 00573 case ASN1_TYPE_BMP_STRING: 00574 //Append prefix 00575 TRACE_DEBUG("%s", prefix[level + 1]); 00576 //Dump the entire string 00577 for(i = 0; i < tag.length; i++) 00578 TRACE_DEBUG("%c", tag.value[i]); 00579 //Add a line feed 00580 TRACE_DEBUG("\r\n"); 00581 break; 00582 //UTC time? 00583 case ASN1_TYPE_UTC_TIME: 00584 //Check length 00585 if(tag.length < 13) 00586 return ERROR_WRONG_ENCODING; 00587 //The encoding shall terminate with a "Z" 00588 if(tag.value[tag.length - 1] != 'Z') 00589 return ERROR_WRONG_ENCODING; 00590 00591 //Append prefix 00592 TRACE_DEBUG("%s", prefix[level + 1]); 00593 //Display date 00594 TRACE_DEBUG("%c%c/%c%c/%c%c ", tag.value[0], tag.value[1], 00595 tag.value[2], tag.value[3], tag.value[4], tag.value[5]); 00596 //Display time 00597 TRACE_DEBUG("%c%c:%c%c:%c%c", tag.value[6], tag.value[7], 00598 tag.value[8], tag.value[9], tag.value[10], tag.value[11]); 00599 //Add a line feed 00600 TRACE_DEBUG("\r\n"); 00601 break; 00602 //Generalized time? 00603 case ASN1_TYPE_GENERALIZED_TIME: 00604 //Check length 00605 if(tag.length < 13) 00606 return ERROR_WRONG_ENCODING; 00607 //The encoding shall terminate with a "Z" 00608 if(tag.value[tag.length - 1] != 'Z') 00609 return ERROR_WRONG_ENCODING; 00610 00611 //Append prefix 00612 TRACE_DEBUG("%s", prefix[level + 1]); 00613 //Display date 00614 TRACE_DEBUG("%c%c%c%c/%c%c/%c%c ", tag.value[0], tag.value[1], tag.value[2], 00615 tag.value[3], tag.value[4], tag.value[5], tag.value[6], tag.value[7]); 00616 //Display time 00617 TRACE_DEBUG("%c%c:%c%c:%c%c", tag.value[8], tag.value[9], 00618 tag.value[10], tag.value[11], tag.value[12], tag.value[13]); 00619 //Add a line feed 00620 TRACE_DEBUG("\r\n"); 00621 break; 00622 //Any other type? 00623 default: 00624 //Dump the contents of the tag 00625 TRACE_DEBUG_ARRAY(prefix[level + 1], tag.value, tag.length); 00626 break; 00627 } 00628 } 00629 } 00630 #endif 00631 00632 //ASN.1 object successfully decoded 00633 return NO_ERROR; 00634 } 00635 00636 #endif 00637
Generated on Tue Jul 12 2022 17:10:12 by
