Webserver+3d print

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers pem.c Source File

pem.c

Go to the documentation of this file.
00001 /**
00002  * @file pem.c
00003  * @brief PEM (Privacy-Enhanced Mail)
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 "pem.h"
00036 #include "asn1.h"
00037 #include "base64.h"
00038 #include "mpi.h"
00039 #include "debug.h"
00040 
00041 //Check crypto library configuration
00042 #if (PEM_SUPPORT == ENABLED)
00043 
00044 
00045 /**
00046  * @brief Decode a PEM file containing Diffie-Hellman parameters
00047  * @param[in] input Pointer to the PEM structure
00048  * @param[in] length Length of the PEM structure
00049  * @param[out] params Diffie-Hellman parameters resulting from the parsing process
00050  * @return Error code
00051  **/
00052 
00053 error_t pemReadDhParameters(const char_t *input, size_t length, DhParameters *params)
00054 {
00055 #if (DH_SUPPORT == ENABLED)
00056    error_t error;
00057    size_t i;
00058    size_t j;
00059    int_t k;
00060    char_t *buffer;
00061    const uint8_t *data;
00062    Asn1Tag tag;
00063 
00064    //Check parameters
00065    if(input == NULL && length != 0)
00066       return ERROR_INVALID_PARAMETER;
00067    if(params == NULL)
00068       return ERROR_INVALID_PARAMETER;
00069 
00070    //Search for the beginning tag
00071    k = pemSearchTag(input, length, "-----BEGIN DH PARAMETERS-----", 29);
00072    //Failed to find the specified tag?
00073    if(k < 0)
00074       return ERROR_INVALID_SYNTAX;
00075 
00076    //Advance the pointer over the tag
00077    input += k + 29;
00078    length -= k + 29;
00079 
00080    //Search for the end tag
00081    k = pemSearchTag(input, length, "-----END DH PARAMETERS-----", 27);
00082    //Invalid PEM file?
00083    if(k <= 0)
00084       return ERROR_INVALID_SYNTAX;
00085 
00086    //Length of the PEM structure
00087    length = k;
00088 
00089    //Allocate a memory buffer to hold the decoded data
00090    buffer = cryptoAllocMem(length);
00091    //Failed to allocate memory?
00092    if(buffer == NULL)
00093       return ERROR_OUT_OF_MEMORY;
00094 
00095    //Copy the contents of the PEM structure
00096    memcpy(buffer, input, length);
00097 
00098    //Remove carriage returns and line feeds
00099    for(i = 0, j = 0; i < length; i++)
00100    {
00101       if(buffer[i] != '\r' && buffer[i] != '\n')
00102          buffer[j++] = buffer[i];
00103    }
00104 
00105    //Start of exception handling block
00106    do
00107    {
00108       //The PEM file is Base64 encoded...
00109       error = base64Decode(buffer, j, buffer, &length);
00110       //Failed to decode the file?
00111       if(error)
00112          break;
00113 
00114       //Point to the resulting ASN.1 structure
00115       data = (uint8_t *) buffer;
00116 
00117       //Display ASN.1 structure
00118       error = asn1DumpObject(data, length, 0);
00119       //Any error to report?
00120       if(error)
00121          break;
00122 
00123       //The Diffie-Hellman parameters are encapsulated within a sequence
00124       error = asn1ReadTag(data, length, &tag);
00125       //Failed to decode ASN.1 tag?
00126       if(error)
00127          break;
00128 
00129       //Enforce encoding, class and type
00130       error = asn1CheckTag(&tag, TRUE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_SEQUENCE);
00131       //The tag does not match the criteria?
00132       if(error)
00133          break;
00134 
00135       //Point to the first field of the sequence
00136       data = tag.value;
00137       length = tag.length;
00138 
00139       //Read the prime modulus
00140       error = asn1ReadTag(data, length, &tag);
00141       //Failed to decode ASN.1 tag?
00142       if(error)
00143          break;
00144 
00145       //Enforce encoding, class and type
00146       error = asn1CheckTag(&tag, FALSE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_INTEGER);
00147       //The tag does not match the criteria?
00148       if(error)
00149          break;
00150 
00151       //Convert the prime modulus to a multiple precision integer
00152       error = mpiReadRaw(&params->p, tag.value, tag.length);
00153       //Any error to report?
00154       if(error)
00155          break;
00156 
00157       //Point to the next field
00158       data += tag.totalLength;
00159       length -= tag.totalLength;
00160 
00161       //Read the generator
00162       error = asn1ReadTag(data, length, &tag);
00163       //Failed to decode ASN.1 tag?
00164       if(error)
00165          break;
00166 
00167       //Enforce encoding, class and type
00168       error = asn1CheckTag(&tag, FALSE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_INTEGER);
00169       //The tag does not match the criteria?
00170       if(error)
00171          break;
00172 
00173       //Convert the generator to a multiple precision integer
00174       error = mpiReadRaw(&params->g, tag.value, tag.length);
00175       //Any error to report?
00176       if(error)
00177          break;
00178 
00179       //Debug message
00180       TRACE_DEBUG("Diffie-Hellman parameters:\r\n");
00181       TRACE_DEBUG("  Prime modulus:\r\n");
00182       TRACE_DEBUG_MPI("    ", &params->p);
00183       TRACE_DEBUG("  Generator:\r\n");
00184       TRACE_DEBUG_MPI("    ", &params->g);
00185 
00186       //End of exception handling block
00187    } while(0);
00188 
00189    //Release previously allocated memory
00190    cryptoFreeMem(buffer);
00191 
00192    //Any error to report?
00193    if(error)
00194    {
00195       //Clean up side effects
00196       mpiFree(&params->p);
00197       mpiFree(&params->g);
00198    }
00199 
00200    //Return status code
00201    return error;
00202 #else
00203    //Not implemented
00204    return ERROR_NOT_IMPLEMENTED;
00205 #endif
00206 }
00207 
00208 
00209 /**
00210  * @brief Decode a PEM file containing a RSA private key
00211  * @param[in] input Pointer to the PEM structure
00212  * @param[in] length Length of the PEM structure
00213  * @param[out] key RSA private key resulting from the parsing process
00214  * @return Error code
00215  **/
00216 
00217 error_t pemReadRsaPrivateKey(const char_t *input, size_t length, RsaPrivateKey *key)
00218 {
00219 #if (RSA_SUPPORT == ENABLED)
00220    error_t error;
00221    size_t i;
00222    size_t j;
00223    int_t k;
00224    char_t *buffer;
00225    const uint8_t *data;
00226    Asn1Tag tag;
00227 
00228    //Check parameters
00229    if(input == NULL && length != 0)
00230       return ERROR_INVALID_PARAMETER;
00231    if(key == NULL)
00232       return ERROR_INVALID_PARAMETER;
00233 
00234    //Search for the beginning tag
00235    k = pemSearchTag(input, length, "-----BEGIN RSA PRIVATE KEY-----", 31);
00236    //Failed to find the specified tag?
00237    if(k < 0)
00238       return ERROR_INVALID_SYNTAX;
00239 
00240    //Advance the pointer over the tag
00241    input += k + 31;
00242    length -= k + 31;
00243 
00244    //Search for the end tag
00245    k = pemSearchTag(input, length, "-----END RSA PRIVATE KEY-----", 29);
00246    //Invalid PEM file?
00247    if(k <= 0)
00248       return ERROR_INVALID_SYNTAX;
00249 
00250    //Length of the PEM structure
00251    length = k;
00252 
00253    //Allocate a memory buffer to hold the decoded data
00254    buffer = cryptoAllocMem(length);
00255    //Failed to allocate memory?
00256    if(buffer == NULL)
00257       return ERROR_OUT_OF_MEMORY;
00258 
00259    //Copy the contents of the PEM structure
00260    memcpy(buffer, input, length);
00261 
00262    //Remove carriage returns and line feeds
00263    for(i = 0, j = 0; i < length; i++)
00264    {
00265       if(buffer[i] != '\r' && buffer[i] != '\n')
00266          buffer[j++] = buffer[i];
00267    }
00268 
00269    //Start of exception handling block
00270    do
00271    {
00272       //The PEM file is Base64 encoded...
00273       error = base64Decode(buffer, j, buffer, &length);
00274       //Failed to decode the file?
00275       if(error)
00276          break;
00277 
00278       //Point to the resulting ASN.1 structure
00279       data = (uint8_t *) buffer;
00280 
00281       //Display ASN.1 structure
00282       error = asn1DumpObject(data, length, 0);
00283       //Any error to report?
00284       if(error)
00285          break;
00286 
00287       //The RSA private key is encapsulated within a sequence
00288       error = asn1ReadTag(data, length, &tag);
00289       //Failed to decode ASN.1 tag?
00290       if(error)
00291          break;
00292 
00293       //Enforce encoding, class and type
00294       error = asn1CheckTag(&tag, TRUE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_SEQUENCE);
00295       //The tag does not match the criteria?
00296       if(error)
00297          break;
00298 
00299       //Point to the first field of the sequence
00300       data = tag.value;
00301       length = tag.length;
00302 
00303       //Read the version
00304       error = asn1ReadTag(data, length, &tag);
00305       //Failed to decode ASN.1 tag?
00306       if(error)
00307          break;
00308 
00309       //Enforce encoding, class and type
00310       error = asn1CheckTag(&tag, FALSE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_INTEGER);
00311       //The tag does not match the criteria?
00312       if(error)
00313          break;
00314 
00315       //Skip the version field
00316       data += tag.totalLength;
00317       length -= tag.totalLength;
00318 
00319       //Read the modulus
00320       error = asn1ReadTag(data, length, &tag);
00321       //Failed to decode ASN.1 tag?
00322       if(error)
00323          break;
00324 
00325       //Enforce encoding, class and type
00326       error = asn1CheckTag(&tag, FALSE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_INTEGER);
00327       //The tag does not match the criteria?
00328       if(error)
00329          break;
00330 
00331       //Convert the modulus to a multiple precision integer
00332       error = mpiReadRaw(&key->n, tag.value, tag.length);
00333       //Any error to report?
00334       if(error)
00335          break;
00336 
00337       //Point to the next field
00338       data += tag.totalLength;
00339       length -= tag.totalLength;
00340 
00341       //Read the public exponent
00342       error = asn1ReadTag(data, length, &tag);
00343       //Failed to decode ASN.1 tag?
00344       if(error)
00345          break;
00346 
00347       //Enforce encoding, class and type
00348       error = asn1CheckTag(&tag, FALSE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_INTEGER);
00349       //The tag does not match the criteria?
00350       if(error)
00351          break;
00352 
00353       //Convert the public exponent to a multiple precision integer
00354       error = mpiReadRaw(&key->e, tag.value, tag.length);
00355       //Any error to report?
00356       if(error)
00357          break;
00358 
00359       //Point to the next field
00360       data += tag.totalLength;
00361       length -= tag.totalLength;
00362 
00363       //Read the private exponent
00364       error = asn1ReadTag(data, length, &tag);
00365       //Failed to decode ASN.1 tag?
00366       if(error)
00367          break;
00368 
00369       //Enforce encoding, class and type
00370       error = asn1CheckTag(&tag, FALSE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_INTEGER);
00371       //The tag does not match the criteria?
00372       if(error)
00373          break;
00374 
00375       //Convert the private exponent to a multiple precision integer
00376       error = mpiReadRaw(&key->d, tag.value, tag.length);
00377       //Any error to report?
00378       if(error)
00379          break;
00380 
00381       //Point to the next field
00382       data += tag.totalLength;
00383       length -= tag.totalLength;
00384 
00385       //Read the first factor
00386       error = asn1ReadTag(data, length, &tag);
00387       //Failed to decode ASN.1 tag?
00388       if(error)
00389          break;
00390 
00391       //Enforce encoding, class and type
00392       error = asn1CheckTag(&tag, FALSE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_INTEGER);
00393       //The tag does not match the criteria?
00394       if(error)
00395          break;
00396 
00397       //Convert the first factor to a multiple precision integer
00398       error = mpiReadRaw(&key->p, tag.value, tag.length);
00399       //Any error to report?
00400       if(error)
00401          break;
00402 
00403       //Point to the next field
00404       data += tag.totalLength;
00405       length -= tag.totalLength;
00406 
00407       //Read the second factor
00408       error = asn1ReadTag(data, length, &tag);
00409       //Failed to decode ASN.1 tag?
00410       if(error)
00411          break;
00412 
00413       //Enforce encoding, class and type
00414       error = asn1CheckTag(&tag, FALSE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_INTEGER);
00415       //The tag does not match the criteria?
00416       if(error)
00417          break;
00418 
00419       //Convert the second factor to a multiple precision integer
00420       error = mpiReadRaw(&key->q, tag.value, tag.length);
00421       //Any error to report?
00422       if(error)
00423          break;
00424 
00425       //Point to the next field
00426       data += tag.totalLength;
00427       length -= tag.totalLength;
00428 
00429       //Read the first exponent
00430       error = asn1ReadTag(data, length, &tag);
00431       //Failed to decode ASN.1 tag?
00432       if(error)
00433          break;
00434 
00435       //Enforce encoding, class and type
00436       error = asn1CheckTag(&tag, FALSE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_INTEGER);
00437       //The tag does not match the criteria?
00438       if(error)
00439          break;
00440 
00441       //Convert the first exponent to a multiple precision integer
00442       error = mpiReadRaw(&key->dp, tag.value, tag.length);
00443       //Any error to report?
00444       if(error)
00445          break;
00446 
00447       //Point to the next field
00448       data += tag.totalLength;
00449       length -= tag.totalLength;
00450 
00451       //Read the second exponent
00452       error = asn1ReadTag(data, length, &tag);
00453       //Failed to decode ASN.1 tag?
00454       if(error)
00455          break;
00456 
00457       //Enforce encoding, class and type
00458       error = asn1CheckTag(&tag, FALSE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_INTEGER);
00459       //The tag does not match the criteria?
00460       if(error)
00461          break;
00462 
00463       //Convert the second exponent to a multiple precision integer
00464       error = mpiReadRaw(&key->dq, tag.value, tag.length);
00465       //Any error to report?
00466       if(error)
00467          break;
00468 
00469       //Point to the next field
00470       data += tag.totalLength;
00471       length -= tag.totalLength;
00472 
00473       //Read the coefficient
00474       error = asn1ReadTag(data, length, &tag);
00475       //Failed to decode ASN.1 tag?
00476       if(error)
00477          break;
00478 
00479       //Enforce encoding, class and type
00480       error = asn1CheckTag(&tag, FALSE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_INTEGER);
00481       //The tag does not match the criteria?
00482       if(error)
00483          break;
00484 
00485       //Convert the coefficient to a multiple precision integer
00486       error = mpiReadRaw(&key->qinv, tag.value, tag.length);
00487       //Any error to report?
00488       if(error)
00489          break;
00490 
00491       //Debug message
00492       TRACE_DEBUG("RSA private key:\r\n");
00493       TRACE_DEBUG("  Modulus:\r\n");
00494       TRACE_DEBUG_MPI("    ", &key->n);
00495       TRACE_DEBUG("  Public exponent:\r\n");
00496       TRACE_DEBUG_MPI("    ", &key->e);
00497       TRACE_DEBUG("  Private exponent:\r\n");
00498       TRACE_DEBUG_MPI("    ", &key->d);
00499       TRACE_DEBUG("  Prime 1:\r\n");
00500       TRACE_DEBUG_MPI("    ", &key->p);
00501       TRACE_DEBUG("  Prime 2:\r\n");
00502       TRACE_DEBUG_MPI("    ", &key->q);
00503       TRACE_DEBUG("  Prime exponent 1:\r\n");
00504       TRACE_DEBUG_MPI("    ", &key->dp);
00505       TRACE_DEBUG("  Prime exponent 2:\r\n");
00506       TRACE_DEBUG_MPI("    ", &key->dq);
00507       TRACE_DEBUG("  Coefficient:\r\n");
00508       TRACE_DEBUG_MPI("    ", &key->qinv);
00509 
00510       //End of exception handling block
00511    } while(0);
00512 
00513    //Release previously allocated memory
00514    cryptoFreeMem(buffer);
00515 
00516    //Clean up side effects if necessary
00517    if(error)
00518       rsaFreePrivateKey(key);
00519 
00520    //Return status code
00521    return error;
00522 #else
00523    //Not implemented
00524    return ERROR_NOT_IMPLEMENTED;
00525 #endif
00526 }
00527 
00528 
00529 /**
00530  * @brief Decode a PEM file containing a DSA private key
00531  * @param[in] input Pointer to the PEM structure
00532  * @param[in] length Length of the PEM structure
00533  * @param[out] key DSA private key resulting from the parsing process
00534  * @return Error code
00535  **/
00536 
00537 error_t pemReadDsaPrivateKey(const char_t *input, size_t length, DsaPrivateKey *key)
00538 {
00539 #if (DSA_SUPPORT == ENABLED)
00540    error_t error;
00541    size_t i;
00542    size_t j;
00543    int_t k;
00544    char_t *buffer;
00545    const uint8_t *data;
00546    Asn1Tag tag;
00547 
00548    //Check parameters
00549    if(input == NULL && length != 0)
00550       return ERROR_INVALID_PARAMETER;
00551    if(key == NULL)
00552       return ERROR_INVALID_PARAMETER;
00553 
00554    //Search for the beginning tag
00555    k = pemSearchTag(input, length, "-----BEGIN DSA PRIVATE KEY-----", 31);
00556    //Failed to find the specified tag?
00557    if(k < 0)
00558       return ERROR_INVALID_SYNTAX;
00559 
00560    //Advance the pointer over the tag
00561    input += k + 31;
00562    length -= k + 31;
00563 
00564    //Search for the end tag
00565    k = pemSearchTag(input, length, "-----END DSA PRIVATE KEY-----", 29);
00566    //Invalid PEM file?
00567    if(k <= 0)
00568       return ERROR_INVALID_SYNTAX;
00569 
00570    //Length of the PEM structure
00571    length = k;
00572 
00573    //Allocate a memory buffer to hold the decoded data
00574    buffer = cryptoAllocMem(length);
00575    //Failed to allocate memory?
00576    if(buffer == NULL)
00577       return ERROR_OUT_OF_MEMORY;
00578 
00579    //Copy the contents of the PEM structure
00580    memcpy(buffer, input, length);
00581 
00582    //Remove carriage returns and line feeds
00583    for(i = 0, j = 0; i < length; i++)
00584    {
00585       if(buffer[i] != '\r' && buffer[i] != '\n')
00586          buffer[j++] = buffer[i];
00587    }
00588 
00589    //Start of exception handling block
00590    do
00591    {
00592       //The PEM file is Base64 encoded...
00593       error = base64Decode(buffer, j, buffer, &length);
00594       //Failed to decode the file?
00595       if(error)
00596          break;
00597 
00598       //Point to the resulting ASN.1 structure
00599       data = (uint8_t *) buffer;
00600 
00601       //Display ASN.1 structure
00602       error = asn1DumpObject(data, length, 0);
00603       //Any error to report?
00604       if(error)
00605          break;
00606 
00607       //The DSA private key is encapsulated within a sequence
00608       error = asn1ReadTag(data, length, &tag);
00609       //Failed to decode ASN.1 tag?
00610       if(error)
00611          break;
00612 
00613       //Enforce encoding, class and type
00614       error = asn1CheckTag(&tag, TRUE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_SEQUENCE);
00615       //The tag does not match the criteria?
00616       if(error)
00617          break;
00618 
00619       //Point to the first field of the sequence
00620       data = tag.value;
00621       length = tag.length;
00622 
00623       //Read the version
00624       error = asn1ReadTag(data, length, &tag);
00625       //Failed to decode ASN.1 tag?
00626       if(error)
00627          break;
00628 
00629       //Enforce encoding, class and type
00630       error = asn1CheckTag(&tag, FALSE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_INTEGER);
00631       //The tag does not match the criteria?
00632       if(error)
00633          break;
00634 
00635       //Skip the version field
00636       data += tag.totalLength;
00637       length -= tag.totalLength;
00638 
00639       //Read p
00640       error = asn1ReadTag(data, length, &tag);
00641       //Failed to decode ASN.1 tag?
00642       if(error)
00643          break;
00644 
00645       //Enforce encoding, class and type
00646       error = asn1CheckTag(&tag, FALSE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_INTEGER);
00647       //The tag does not match the criteria?
00648       if(error)
00649          break;
00650 
00651       //Convert p to a multiple precision integer
00652       error = mpiReadRaw(&key->p, tag.value, tag.length);
00653       //Any error to report?
00654       if(error)
00655          break;
00656 
00657       //Point to the next field
00658       data += tag.totalLength;
00659       length -= tag.totalLength;
00660 
00661       //Read q
00662       error = asn1ReadTag(data, length, &tag);
00663       //Failed to decode ASN.1 tag?
00664       if(error)
00665          break;
00666 
00667       //Enforce encoding, class and type
00668       error = asn1CheckTag(&tag, FALSE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_INTEGER);
00669       //The tag does not match the criteria?
00670       if(error)
00671          break;
00672 
00673       //Convert q to a multiple precision integer
00674       error = mpiReadRaw(&key->q, tag.value, tag.length);
00675       //Any error to report?
00676       if(error)
00677          break;
00678 
00679       //Point to the next field
00680       data += tag.totalLength;
00681       length -= tag.totalLength;
00682 
00683       //Read g
00684       error = asn1ReadTag(data, length, &tag);
00685       //Failed to decode ASN.1 tag?
00686       if(error)
00687          break;
00688 
00689       //Enforce encoding, class and type
00690       error = asn1CheckTag(&tag, FALSE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_INTEGER);
00691       //The tag does not match the criteria?
00692       if(error)
00693          break;
00694 
00695       //Convert g to a multiple precision integer
00696       error = mpiReadRaw(&key->g, tag.value, tag.length);
00697       //Any error to report?
00698       if(error)
00699          break;
00700 
00701       //Point to the next field
00702       data += tag.totalLength;
00703       length -= tag.totalLength;
00704 
00705       //Read the public value
00706       error = asn1ReadTag(data, length, &tag);
00707       //Failed to decode ASN.1 tag?
00708       if(error)
00709          break;
00710 
00711       //Enforce encoding, class and type
00712       error = asn1CheckTag(&tag, FALSE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_INTEGER);
00713       //The tag does not match the criteria?
00714       if(error)
00715          break;
00716 
00717       //Point to the next field
00718       data += tag.totalLength;
00719       length -= tag.totalLength;
00720 
00721       //Read the private value
00722       error = asn1ReadTag(data, length, &tag);
00723       //Failed to decode ASN.1 tag?
00724       if(error)
00725          break;
00726 
00727       //Enforce encoding, class and type
00728       error = asn1CheckTag(&tag, FALSE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_INTEGER);
00729       //The tag does not match the criteria?
00730       if(error)
00731          break;
00732 
00733       //Convert the private value to a multiple precision integer
00734       error = mpiReadRaw(&key->x, tag.value, tag.length);
00735       //Any error to report?
00736       if(error)
00737          break;
00738 
00739       //Debug message
00740       TRACE_DEBUG("DSA private key:\r\n");
00741       TRACE_DEBUG("  p:\r\n");
00742       TRACE_DEBUG_MPI("    ", &key->p);
00743       TRACE_DEBUG("  q:\r\n");
00744       TRACE_DEBUG_MPI("    ", &key->q);
00745       TRACE_DEBUG("  g:\r\n");
00746       TRACE_DEBUG_MPI("    ", &key->g);
00747       TRACE_DEBUG("  x:\r\n");
00748       TRACE_DEBUG_MPI("    ", &key->x);
00749 
00750       //End of exception handling block
00751    } while(0);
00752 
00753    //Release previously allocated memory
00754    cryptoFreeMem(buffer);
00755 
00756    //Clean up side effects if necessary
00757    if(error)
00758       dsaFreePrivateKey(key);
00759 
00760    //Return status code
00761    return error;
00762 #else
00763    //Not implemented
00764    return ERROR_NOT_IMPLEMENTED;
00765 #endif
00766 }
00767 
00768 
00769 /**
00770  * @brief Decode a PEM file containing EC domain parameters
00771  * @param[in] input Pointer to the PEM structure
00772  * @param[in] length Length of the PEM structure
00773  * @param[out] params EC domain parameters
00774  * @return Error code
00775  **/
00776 
00777 error_t pemReadEcParameters(const char_t *input, size_t length, EcDomainParameters *params)
00778 {
00779 #if (EC_SUPPORT == ENABLED)
00780    error_t error;
00781    size_t i;
00782    size_t j;
00783    int_t k;
00784    char_t *buffer;
00785    const uint8_t *data;
00786    Asn1Tag tag;
00787    const EcCurveInfo *curveInfo;
00788 
00789    //Check parameters
00790    if(input == NULL && length != 0)
00791       return ERROR_INVALID_PARAMETER;
00792    if(params == NULL)
00793       return ERROR_INVALID_PARAMETER;
00794 
00795    //Check the format of the PEM file
00796    if(pemSearchTag(input, length, "-----BEGIN EC PARAMETERS-----", 29) >= 0)
00797    {
00798       //Search for the beginning tag
00799       k = pemSearchTag(input, length, "-----BEGIN EC PARAMETERS-----", 29);
00800       //Failed to find the specified tag?
00801       if(k < 0)
00802          return ERROR_INVALID_SYNTAX;
00803 
00804       //Advance the pointer over the tag
00805       input += k + 29;
00806       length -= k + 29;
00807 
00808       //Search for the end tag
00809       k = pemSearchTag(input, length, "-----END EC PARAMETERS-----", 27);
00810       //Invalid PEM file?
00811       if(k <= 0)
00812          return ERROR_INVALID_SYNTAX;
00813 
00814       //Length of the PEM structure
00815       length = k;
00816 
00817       //Allocate a memory buffer to hold the decoded data
00818       buffer = cryptoAllocMem(length);
00819       //Failed to allocate memory?
00820       if(buffer == NULL)
00821          return ERROR_OUT_OF_MEMORY;
00822 
00823       //Copy the contents of the PEM structure
00824       memcpy(buffer, input, length);
00825 
00826       //Remove carriage returns and line feeds
00827       for(i = 0, j = 0; i < length; i++)
00828       {
00829          if(buffer[i] != '\r' && buffer[i] != '\n')
00830             buffer[j++] = buffer[i];
00831       }
00832 
00833       //Start of exception handling block
00834       do
00835       {
00836          //The PEM file is Base64 encoded...
00837          error = base64Decode(buffer, j, buffer, &length);
00838          //Failed to decode the file?
00839          if(error)
00840             break;
00841 
00842          //Point to the resulting ASN.1 structure
00843          data = (uint8_t *) buffer;
00844 
00845          //Display ASN.1 structure
00846          error = asn1DumpObject(data, length, 0);
00847          //Any error to report?
00848          if(error)
00849             break;
00850 
00851          //Read the curve identifier
00852          error = asn1ReadTag(data, length, &tag);
00853          //Failed to decode ASN.1 tag?
00854          if(error)
00855             break;
00856 
00857          //Enforce encoding, class and type
00858          error = asn1CheckTag(&tag, FALSE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_OBJECT_IDENTIFIER);
00859          //The tag does not match the criteria?
00860          if(error)
00861             break;
00862 
00863          //Retrieve EC domain parameters
00864          curveInfo = ecGetCurveInfo(tag.value, tag.length);
00865          //Make sure the specified elliptic curve is supported
00866          if(curveInfo == NULL)
00867          {
00868             //Report an error
00869             error = ERROR_ILLEGAL_PARAMETER;
00870             //Exit immediately
00871             break;
00872          }
00873 
00874          //Load EC domain parameters
00875          error = ecLoadDomainParameters(params, curveInfo);
00876          //Any error to report?
00877          if(error)
00878             break;
00879 
00880          //End of exception handling block
00881       } while(0);
00882    }
00883    else
00884    {
00885       //Search for the beginning tag
00886       k = pemSearchTag(input, length, "-----BEGIN PRIVATE KEY-----", 27);
00887       //Failed to find the specified tag?
00888       if(k < 0)
00889          return ERROR_INVALID_SYNTAX;
00890 
00891       //Advance the pointer over the tag
00892       input += k + 27;
00893       length -= k + 27;
00894 
00895       //Search for the end tag
00896       k = pemSearchTag(input, length, "-----END PRIVATE KEY-----", 25);
00897       //Invalid PEM file?
00898       if(k <= 0)
00899          return ERROR_INVALID_SYNTAX;
00900 
00901       //Length of the PEM structure
00902       length = k;
00903 
00904       //Allocate a memory buffer to hold the decoded data
00905       buffer = cryptoAllocMem(length);
00906       //Failed to allocate memory?
00907       if(buffer == NULL)
00908          return ERROR_OUT_OF_MEMORY;
00909 
00910       //Copy the contents of the PEM structure
00911       memcpy(buffer, input, length);
00912 
00913       //Remove carriage returns and line feeds
00914       for(i = 0, j = 0; i < length; i++)
00915       {
00916          if(buffer[i] != '\r' && buffer[i] != '\n')
00917             buffer[j++] = buffer[i];
00918       }
00919 
00920       //Start of exception handling block
00921       do
00922       {
00923          //The PEM file is Base64 encoded...
00924          error = base64Decode(buffer, j, buffer, &length);
00925          //Failed to decode the file?
00926          if(error)
00927             break;
00928 
00929          //Point to the resulting ASN.1 structure
00930          data = (uint8_t *) buffer;
00931 
00932          //Display ASN.1 structure
00933          error = asn1DumpObject(data, length, 0);
00934          //Any error to report?
00935          if(error)
00936             break;
00937 
00938          //The private key is encapsulated within a sequence
00939          error = asn1ReadTag(data, length, &tag);
00940          //Failed to decode ASN.1 tag?
00941          if(error)
00942             break;
00943 
00944          //Enforce encoding, class and type
00945          error = asn1CheckTag(&tag, TRUE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_SEQUENCE);
00946          //The tag does not match the criteria?
00947          if(error)
00948             break;
00949 
00950          //Point to the first field of the sequence
00951          data = tag.value;
00952          length = tag.length;
00953 
00954          //Read the Version field
00955          error = asn1ReadTag(data, length, &tag);
00956          //Failed to decode ASN.1 tag?
00957          if(error)
00958             break;
00959 
00960          //Enforce encoding, class and type
00961          error = asn1CheckTag(&tag, FALSE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_INTEGER);
00962          //The tag does not match the criteria?
00963          if(error)
00964             break;
00965 
00966          //Skip the Version field
00967          data += tag.totalLength;
00968          length -= tag.totalLength;
00969 
00970          //Read the PrivateKeyAlgorithmIdentifier field
00971          error = asn1ReadTag(data, length, &tag);
00972          //Failed to decode ASN.1 tag?
00973          if(error)
00974             break;
00975 
00976          //Enforce encoding, class and type
00977          error = asn1CheckTag(&tag, TRUE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_SEQUENCE);
00978          //The tag does not match the criteria?
00979          if(error)
00980             break;
00981 
00982          //Point to the first field of the sequence
00983          data = tag.value;
00984          length = tag.length;
00985 
00986          //Read the algorithm identifier (OID)
00987          error = asn1ReadTag(data, length, &tag);
00988          //Failed to decode ASN.1 tag?
00989          if(error)
00990             break;
00991 
00992          //Check algorithm identifier
00993          error = asn1CheckOid(&tag, EC_PUBLIC_KEY_OID, sizeof(EC_PUBLIC_KEY_OID));
00994          //Wrong identifier?
00995          if(error)
00996             break;
00997 
00998          //Point to the next field
00999          data += tag.totalLength;
01000          length += tag.totalLength;
01001 
01002          //Read namedCurve field
01003          error = asn1ReadTag(data, length, &tag);
01004          //Failed to decode ASN.1 tag?
01005          if(error)
01006             break;
01007 
01008          //Enforce encoding, class and type
01009          error = asn1CheckTag(&tag, FALSE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_OBJECT_IDENTIFIER);
01010          //The tag does not match the criteria?
01011          if(error)
01012             break;
01013 
01014          //Retrieve EC domain parameters
01015          curveInfo = ecGetCurveInfo(tag.value, tag.length);
01016          //Make sure the specified elliptic curve is supported
01017          if(curveInfo == NULL)
01018          {
01019             //Report an error
01020             error = ERROR_ILLEGAL_PARAMETER;
01021             //Exit immediately
01022             break;
01023          }
01024 
01025          //Load EC domain parameters
01026          error = ecLoadDomainParameters(params, curveInfo);
01027          //Any error to report?
01028          if(error)
01029             break;
01030 
01031          //End of exception handling block
01032       } while(0);
01033    }
01034 
01035    //Release previously allocated memory
01036    cryptoFreeMem(buffer);
01037 
01038    //Clean up side effects if necessary
01039    if(error)
01040       ecFreeDomainParameters(params);
01041 
01042    //Return status code
01043    return error;
01044 #else
01045    //Not implemented
01046    return ERROR_NOT_IMPLEMENTED;
01047 #endif
01048 }
01049 
01050 
01051 /**
01052  * @brief Decode a PEM file containing an EC private key
01053  * @param[in] input Pointer to the PEM structure
01054  * @param[in] length Length of the PEM structure
01055  * @param[out] key EC private key resulting from the parsing process
01056  * @return Error code
01057  **/
01058 
01059 error_t pemReadEcPrivateKey(const char_t *input, size_t length, Mpi *key)
01060 {
01061 #if (EC_SUPPORT == ENABLED)
01062    error_t error;
01063    size_t i;
01064    size_t j;
01065    int_t k;
01066    char_t *buffer;
01067    const uint8_t *data;
01068    Asn1Tag tag;
01069 
01070    //Check parameters
01071    if(input == NULL && length != 0)
01072       return ERROR_INVALID_PARAMETER;
01073    if(key == NULL)
01074       return ERROR_INVALID_PARAMETER;
01075 
01076    //Check the format of the PEM file
01077    if(pemSearchTag(input, length, "-----BEGIN EC PRIVATE KEY-----", 30) >= 0)
01078    {
01079       //Search for the beginning tag
01080       k = pemSearchTag(input, length, "-----BEGIN EC PRIVATE KEY-----", 30);
01081       //Failed to find the specified tag?
01082       if(k < 0)
01083          return ERROR_INVALID_SYNTAX;
01084 
01085       //Advance the pointer over the tag
01086       input += k + 30;
01087       length -= k + 30;
01088 
01089       //Search for the end tag
01090       k = pemSearchTag(input, length, "-----END EC PRIVATE KEY-----", 28);
01091       //Invalid PEM file?
01092       if(k <= 0)
01093          return ERROR_INVALID_SYNTAX;
01094 
01095       //Length of the PEM structure
01096       length = k;
01097 
01098       //Allocate a memory buffer to hold the decoded data
01099       buffer = cryptoAllocMem(length);
01100       //Failed to allocate memory?
01101       if(buffer == NULL)
01102          return ERROR_OUT_OF_MEMORY;
01103 
01104       //Copy the contents of the PEM structure
01105       memcpy(buffer, input, length);
01106 
01107       //Remove carriage returns and line feeds
01108       for(i = 0, j = 0; i < length; i++)
01109       {
01110          if(buffer[i] != '\r' && buffer[i] != '\n')
01111             buffer[j++] = buffer[i];
01112       }
01113 
01114       //Start of exception handling block
01115       do
01116       {
01117          //The PEM file is Base64 encoded...
01118          error = base64Decode(buffer, j, buffer, &length);
01119          //Failed to decode the file?
01120          if(error)
01121             break;
01122 
01123          //Point to the resulting ASN.1 structure
01124          data = (uint8_t *) buffer;
01125 
01126          //Display ASN.1 structure
01127          error = asn1DumpObject(data, length, 0);
01128          //Any error to report?
01129          if(error)
01130             break;
01131 
01132          //The private key is encapsulated within a sequence
01133          error = asn1ReadTag(data, length, &tag);
01134          //Failed to decode ASN.1 tag?
01135          if(error)
01136             break;
01137 
01138          //Enforce encoding, class and type
01139          error = asn1CheckTag(&tag, TRUE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_SEQUENCE);
01140          //The tag does not match the criteria?
01141          if(error)
01142             break;
01143 
01144          //Point to the first field of the sequence
01145          data = tag.value;
01146          length = tag.length;
01147 
01148          //Read the Version field
01149          error = asn1ReadTag(data, length, &tag);
01150          //Failed to decode ASN.1 tag?
01151          if(error)
01152             break;
01153 
01154          //Enforce encoding, class and type
01155          error = asn1CheckTag(&tag, FALSE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_INTEGER);
01156          //The tag does not match the criteria?
01157          if(error)
01158             break;
01159 
01160          //Skip the Version field
01161          data += tag.totalLength;
01162          length -= tag.totalLength;
01163 
01164          //Read the PrivateKey field
01165          error = asn1ReadTag(data, length, &tag);
01166          //Failed to decode ASN.1 tag?
01167          if(error)
01168             break;
01169 
01170          //Enforce encoding, class and type
01171          error = asn1CheckTag(&tag, FALSE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_OCTET_STRING);
01172          //The tag does not match the criteria?
01173          if(error)
01174             break;
01175 
01176          //Read the EC private key
01177          error = mpiReadRaw(key, tag.value, tag.length);
01178          //Any error to report?
01179          if(error)
01180             break;
01181 
01182          //Debug message
01183          TRACE_DEBUG("EC private key:\r\n");
01184          TRACE_DEBUG_MPI("  ", key);
01185 
01186          //End of exception handling block
01187       } while(0);
01188    }
01189    else
01190    {
01191       //Search for the beginning tag
01192       k = pemSearchTag(input, length, "-----BEGIN PRIVATE KEY-----", 27);
01193       //Failed to find the specified tag?
01194       if(k < 0)
01195          return ERROR_INVALID_SYNTAX;
01196 
01197       //Advance the pointer over the tag
01198       input += k + 27;
01199       length -= k + 27;
01200 
01201       //Search for the end tag
01202       k = pemSearchTag(input, length, "-----END PRIVATE KEY-----", 25);
01203       //Invalid PEM file?
01204       if(k <= 0)
01205          return ERROR_INVALID_SYNTAX;
01206 
01207       //Length of the PEM structure
01208       length = k;
01209 
01210       //Allocate a memory buffer to hold the decoded data
01211       buffer = cryptoAllocMem(length);
01212       //Failed to allocate memory?
01213       if(buffer == NULL)
01214          return ERROR_OUT_OF_MEMORY;
01215 
01216       //Copy the contents of the PEM structure
01217       memcpy(buffer, input, length);
01218 
01219       //Remove carriage returns and line feeds
01220       for(i = 0, j = 0; i < length; i++)
01221       {
01222          if(buffer[i] != '\r' && buffer[i] != '\n')
01223             buffer[j++] = buffer[i];
01224       }
01225 
01226       //Start of exception handling block
01227       do
01228       {
01229          //The PEM file is Base64 encoded...
01230          error = base64Decode(buffer, j, buffer, &length);
01231          //Failed to decode the file?
01232          if(error)
01233             break;
01234 
01235          //Point to the resulting ASN.1 structure
01236          data = (uint8_t *) buffer;
01237 
01238          //Display ASN.1 structure
01239          error = asn1DumpObject(data, length, 0);
01240          //Any error to report?
01241          if(error)
01242             break;
01243 
01244          //The private key is encapsulated within a sequence
01245          error = asn1ReadTag(data, length, &tag);
01246          //Failed to decode ASN.1 tag?
01247          if(error)
01248             break;
01249 
01250          //Enforce encoding, class and type
01251          error = asn1CheckTag(&tag, TRUE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_SEQUENCE);
01252          //The tag does not match the criteria?
01253          if(error)
01254             break;
01255 
01256          //Point to the first field of the sequence
01257          data = tag.value;
01258          length = tag.length;
01259 
01260          //Read the Version field
01261          error = asn1ReadTag(data, length, &tag);
01262          //Failed to decode ASN.1 tag?
01263          if(error)
01264             break;
01265 
01266          //Enforce encoding, class and type
01267          error = asn1CheckTag(&tag, FALSE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_INTEGER);
01268          //The tag does not match the criteria?
01269          if(error)
01270             break;
01271 
01272          //Skip the Version field
01273          data += tag.totalLength;
01274          length -= tag.totalLength;
01275 
01276          //Read the PrivateKeyAlgorithmIdentifier field
01277          error = asn1ReadTag(data, length, &tag);
01278          //Failed to decode ASN.1 tag?
01279          if(error)
01280             break;
01281 
01282          //Enforce encoding, class and type
01283          error = asn1CheckTag(&tag, TRUE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_SEQUENCE);
01284          //The tag does not match the criteria?
01285          if(error)
01286             break;
01287 
01288          //Skip the PrivateKeyAlgorithmIdentifier field
01289          data += tag.totalLength;
01290          length -= tag.totalLength;
01291 
01292          //The PrivateKey field is encapsulated within an octet string
01293          error = asn1ReadTag(data, length, &tag);
01294          //Failed to decode ASN.1 tag?
01295          if(error)
01296             break;
01297 
01298          //Enforce encoding, class and type
01299          error = asn1CheckTag(&tag, FALSE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_OCTET_STRING);
01300          //The tag does not match the criteria?
01301          if(error)
01302             break;
01303 
01304          //Display ASN.1 structure
01305          error = asn1DumpObject(tag.value, tag.length, 0);
01306          //Any error to report?
01307          if(error)
01308             break;
01309 
01310          //Read the contents of the PrivateKey structure
01311          error = asn1ReadTag(tag.value, tag.length, &tag);
01312          //Failed to decode ASN.1 tag?
01313          if(error)
01314             break;
01315 
01316          //Enforce encoding, class and type
01317          error = asn1CheckTag(&tag, TRUE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_SEQUENCE);
01318          //The tag does not match the criteria?
01319          if(error)
01320             break;
01321 
01322          //Point to the first field of the sequence
01323          data = tag.value;
01324          length = tag.length;
01325 
01326          //Read the Version field
01327          error = asn1ReadTag(data, length, &tag);
01328          //Failed to decode ASN.1 tag?
01329          if(error)
01330             break;
01331 
01332          //Enforce encoding, class and type
01333          error = asn1CheckTag(&tag, FALSE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_INTEGER);
01334          //The tag does not match the criteria?
01335          if(error)
01336             break;
01337 
01338          //Skip the Version field
01339          data += tag.totalLength;
01340          length -= tag.totalLength;
01341 
01342          //Read the PrivateKey field
01343          error = asn1ReadTag(data, length, &tag);
01344          //Failed to decode ASN.1 tag?
01345          if(error)
01346             break;
01347 
01348          //Enforce encoding, class and type
01349          error = asn1CheckTag(&tag, FALSE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_OCTET_STRING);
01350          //The tag does not match the criteria?
01351          if(error)
01352             break;
01353 
01354          //Read the EC private key
01355          error = mpiReadRaw(key, tag.value, tag.length);
01356          //Any error to report?
01357          if(error)
01358             break;
01359 
01360          //Debug message
01361          TRACE_DEBUG("EC private key:\r\n");
01362          TRACE_DEBUG_MPI("  ", key);
01363 
01364          //End of exception handling block
01365       } while(0);
01366    }
01367 
01368    //Release previously allocated memory
01369    cryptoFreeMem(buffer);
01370 
01371    //Clean up side effects if necessary
01372    if(error)
01373       mpiFree(key);
01374 
01375    //Return status code
01376    return error;
01377 #else
01378    //Not implemented
01379    return ERROR_NOT_IMPLEMENTED;
01380 #endif
01381 }
01382 
01383 
01384 /**
01385  * @brief Decode a PEM file containing a certificate
01386  * @param[in,out] input Pointer to the PEM structure
01387  * @param[in,out] inputLength Length of the PEM structure
01388  * @param[in,out] output Pointer to the DER encoded certificate
01389  * @param[in,out] outputSize Size of the memory block that holds the DER certificate
01390  * @param[out] outputLength Length of the DER encoded certificate
01391  * @return Error code
01392  **/
01393 
01394 error_t pemReadCertificate(const char_t **input, size_t *inputLength,
01395    uint8_t **output, size_t *outputSize, size_t *outputLength)
01396 {
01397    error_t error;
01398    size_t length;
01399    size_t i;
01400    size_t j;
01401    int_t k;
01402 
01403    //Check parameters
01404    if(input == NULL || inputLength == NULL)
01405       return ERROR_INVALID_PARAMETER;
01406    if(output == NULL || outputSize == NULL || outputLength == NULL)
01407       return ERROR_INVALID_PARAMETER;
01408 
01409    //Search for the beginning tag
01410    k = pemSearchTag(*input, *inputLength, "-----BEGIN CERTIFICATE-----", 27);
01411    //Failed to find the specified tag?
01412    if(k < 0)
01413       return ERROR_END_OF_FILE;
01414 
01415    //Advance the input pointer over the tag
01416    *input += k + 27;
01417    *inputLength -= k + 27;
01418 
01419    //Search for the end tag
01420    k = pemSearchTag(*input, *inputLength, "-----END CERTIFICATE-----", 25);
01421    //Invalid PEM file?
01422    if(k <= 0)
01423       return ERROR_INVALID_SYNTAX;
01424 
01425    //Length of the PEM structure
01426    length = k;
01427 
01428    //Increase buffer size?
01429    if(length > *outputSize)
01430    {
01431       //Release previously allocated buffer if necessary
01432       if(*output != NULL)
01433       {
01434          cryptoFreeMem(*output);
01435          *output = NULL;
01436          *outputSize = 0;
01437       }
01438 
01439       //Allocate a memory buffer to hold the decoded data
01440       *output = cryptoAllocMem(length);
01441       //Failed to allocate memory?
01442       if(*output == NULL)
01443          return ERROR_OUT_OF_MEMORY;
01444 
01445       //Record the size of the buffer
01446       *outputSize = length;
01447    }
01448 
01449    //Copy the contents of the PEM structure
01450    memcpy(*output, *input, length);
01451 
01452    //Advance the input pointer over the certificate
01453    *input += length + 25;
01454    *inputLength -= length + 25;
01455 
01456    //Remove carriage returns and line feeds
01457    for(i = 0, j = 0; i < length; i++)
01458    {
01459       if((*output)[i] != '\r' && (*output)[i] != '\n')
01460          (*output)[j++] = (*output)[i];
01461    }
01462 
01463    //Start of exception handling block
01464    do
01465    {
01466       //The PEM file is Base64 encoded...
01467       error = base64Decode((char_t *) *output, j, *output, &length);
01468       //Failed to decode the file?
01469       if(error)
01470          break;
01471 
01472       //Display ASN.1 structure
01473       error = asn1DumpObject(*output, length, 0);
01474       //Any error to report?
01475       if(error)
01476          break;
01477 
01478       //End of exception handling block
01479    } while(0);
01480 
01481    //Clean up side effects
01482    if(error)
01483    {
01484       //Release previously allocated memory
01485       cryptoFreeMem(*output);
01486       *output = NULL;
01487       *outputSize = 0;
01488    }
01489 
01490    //Size of the decoded certificate
01491    *outputLength = length;
01492    //Return status code
01493    return error;
01494 }
01495 
01496 
01497 /**
01498  * @brief Search a string for a given tag
01499  * @param[in] s String to search
01500  * @param[in] sLen Length of the string to search
01501  * @param[in] tag String containing the tag to search for
01502  * @param[in] tagLen Length of the tag
01503  * @return The index of the first occurrence of the tag in the string,
01504  *   or -1 if the tag does not appear in the string
01505  **/
01506 
01507 int_t pemSearchTag(const char_t *s, size_t sLen, const char_t *tag, size_t tagLen)
01508 {
01509    size_t i;
01510    size_t j;
01511 
01512    //Loop through input string
01513    for(i = 0; (i + tagLen) <= sLen; i++)
01514    {
01515       //Compare current substring with the given tag
01516       for(j = 0; j < tagLen; j++)
01517       {
01518          if(s[i + j] != tag[j])
01519             break;
01520       }
01521 
01522       //Check whether the tag has been found
01523       if(j == tagLen)
01524          return i;
01525    }
01526 
01527    //The tag does not appear in the string
01528    return -1;
01529 }
01530 
01531 #endif
01532