/* * Parse one or more CRLs and add them to the chained list */ int x509_crl_parse( x509_crl *chain, const unsigned char *buf, size_t buflen ) { #if defined(POLARSSL_PEM_PARSE_C) int ret; size_t use_len; pem_context pem; int is_pem = 0; if( chain == NULL || buf == NULL ) return( POLARSSL_ERR_X509_BAD_INPUT_DATA ); do { pem_init( &pem ); ret = pem_read_buffer( &pem, "-----BEGIN X509 CRL-----", "-----END X509 CRL-----", buf, NULL, 0, &use_len ); if( ret == 0 ) { /* * Was PEM encoded */ is_pem = 1; buflen -= use_len; buf += use_len; if( ( ret = x509_crl_parse_der( chain, pem.buf, pem.buflen ) ) != 0 ) { return( ret ); } pem_free( &pem ); } else if( ret != POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) { pem_free( &pem ); return( ret ); } } while( is_pem && buflen > 0 ); if( is_pem ) return( 0 ); else #endif /* POLARSSL_PEM_PARSE_C */ return( x509_crl_parse_der( chain, buf, buflen ) ); }
/* * Parse a CSR, allowing for PEM or raw DER encoding */ int x509_csr_parse( x509_csr *csr, const unsigned char *buf, size_t buflen ) { #if defined(POLARSSL_PEM_PARSE_C) int ret; size_t use_len; pem_context pem; #endif /* * Check for valid input */ if( csr == NULL || buf == NULL ) return( POLARSSL_ERR_X509_BAD_INPUT_DATA ); #if defined(POLARSSL_PEM_PARSE_C) pem_init( &pem ); ret = pem_read_buffer( &pem, "-----BEGIN CERTIFICATE REQUEST-----", "-----END CERTIFICATE REQUEST-----", buf, NULL, 0, &use_len ); if( ret == 0 ) { /* * Was PEM encoded, parse the result */ if( ( ret = x509_csr_parse_der( csr, pem.buf, pem.buflen ) ) != 0 ) return( ret ); pem_free( &pem ); return( 0 ); } else if( ret != POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) { pem_free( &pem ); return( ret ); } else #endif /* POLARSSL_PEM_PARSE_C */ return( x509_csr_parse_der( csr, buf, buflen ) ); }
char * path_normalize( char *path ) { pem_t *pemp = pem_alloc( path ); pa_t *pap = pa_alloc( ); char *pep; char *npath; ASSERT( path[ 0 ] == '/' ); while ( ( pep = pem_next( pemp )) != 0 ) { if ( ! strcmp( pep, "" )) { free( ( void * )pep ); continue; } if ( ! strcmp( pep, "." )) { free( ( void * )pep ); continue; } if ( ! strcmp( pep, ".." )) { int ok; free( ( void * )pep ); ok = pa_peel( pap ); if ( ! ok ) { pa_free( pap ); pem_free( pemp ); return 0; } continue; } pa_append( pap, pep ); } npath = pa_gen( pap ); pa_free( pap ); pem_free( pemp ); return npath; }
/* * Parse a public key */ int pk_parse_public_key( pk_context *ctx, const unsigned char *key, size_t keylen ) { int ret; unsigned char *p; #if defined(POLARSSL_PEM_PARSE_C) size_t len; pem_context pem; pem_init( &pem ); ret = pem_read_buffer( &pem, "-----BEGIN PUBLIC KEY-----", "-----END PUBLIC KEY-----", key, NULL, 0, &len ); if( ret == 0 ) { /* * Was PEM encoded */ key = pem.buf; keylen = pem.buflen; } else if( ret != POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) { pem_free( &pem ); return( ret ); } #endif /* POLARSSL_PEM_PARSE_C */ p = (unsigned char *) key; ret = pk_parse_subpubkey( &p, p + keylen, ctx ); #if defined(POLARSSL_PEM_PARSE_C) pem_free( &pem ); #endif return( ret ); }
static int get_name(BIO *bp, char **name, unsigned int flags) { char *linebuf; int ret = 0; int len; /* * Need to hold trailing NUL (accounted for by BIO_gets() and the newline * that will be added by sanitize_line() (the extra '1'). */ linebuf = pem_malloc(LINESIZE + 1, flags); if (linebuf == NULL) { PEMerr(PEM_F_GET_NAME, ERR_R_MALLOC_FAILURE); return 0; } do { len = BIO_gets(bp, linebuf, LINESIZE); if (len <= 0) { PEMerr(PEM_F_GET_NAME, PEM_R_NO_START_LINE); goto err; } /* Strip trailing garbage and standardize ending. */ len = sanitize_line(linebuf, len, flags & ~PEM_FLAG_ONLY_B64); /* Allow leading empty or non-matching lines. */ } while (strncmp(linebuf, beginstr, BEGINLEN) != 0 || len < TAILLEN || strncmp(linebuf + len - TAILLEN, tailstr, TAILLEN) != 0); linebuf[len - TAILLEN] = '\0'; len = len - BEGINLEN - TAILLEN + 1; *name = pem_malloc(len, flags); if (*name == NULL) { PEMerr(PEM_F_GET_NAME, ERR_R_MALLOC_FAILURE); goto err; } memcpy(*name, linebuf + BEGINLEN, len); ret = 1; err: pem_free(linebuf, flags, LINESIZE + 1); return ret; }
static int pem_bytes_read_bio_flags(unsigned char **pdata, long *plen, char **pnm, const char *name, BIO *bp, pem_password_cb *cb, void *u, unsigned int flags) { EVP_CIPHER_INFO cipher; char *nm = NULL, *header = NULL; unsigned char *data = NULL; long len = 0; int ret = 0; do { pem_free(nm, flags, 0); pem_free(header, flags, 0); pem_free(data, flags, len); if (!PEM_read_bio_ex(bp, &nm, &header, &data, &len, flags)) { if (ERR_GET_REASON(ERR_peek_error()) == PEM_R_NO_START_LINE) ERR_add_error_data(2, "Expecting: ", name); return 0; } } while (!check_pem(nm, name)); if (!PEM_get_EVP_CIPHER_INFO(header, &cipher)) goto err; if (!PEM_do_header(&cipher, data, &len, cb, u)) goto err; *pdata = data; *plen = len; if (pnm != NULL) *pnm = nm; ret = 1; err: if (!ret || pnm == NULL) pem_free(nm, flags, 0); pem_free(header, flags, 0); if (!ret) pem_free(data, flags, len); return ret; }
/** * Read in PEM-formatted data from the given BIO. * * By nature of the PEM format, all content must be printable ASCII (except * for line endings). Other characters are malformed input and will be rejected. */ int PEM_read_bio_ex(BIO *bp, char **name_out, char **header, unsigned char **data, long *len_out, unsigned int flags) { EVP_ENCODE_CTX *ctx = EVP_ENCODE_CTX_new(); const BIO_METHOD *bmeth; BIO *headerB = NULL, *dataB = NULL; char *name = NULL; int len, taillen, headerlen, ret = 0; BUF_MEM * buf_mem; if (ctx == NULL) { PEMerr(PEM_F_PEM_READ_BIO_EX, ERR_R_MALLOC_FAILURE); return 0; } *len_out = 0; *name_out = *header = NULL; *data = NULL; if ((flags & PEM_FLAG_EAY_COMPATIBLE) && (flags & PEM_FLAG_ONLY_B64)) { /* These two are mutually incompatible; bail out. */ PEMerr(PEM_F_PEM_READ_BIO_EX, ERR_R_PASSED_INVALID_ARGUMENT); goto end; } bmeth = (flags & PEM_FLAG_SECURE) ? BIO_s_secmem() : BIO_s_mem(); headerB = BIO_new(bmeth); dataB = BIO_new(bmeth); if (headerB == NULL || dataB == NULL) { PEMerr(PEM_F_PEM_READ_BIO_EX, ERR_R_MALLOC_FAILURE); goto end; } if (!get_name(bp, &name, flags)) goto end; if (!get_header_and_data(bp, &headerB, &dataB, name, flags)) goto end; EVP_DecodeInit(ctx); BIO_get_mem_ptr(dataB, &buf_mem); len = buf_mem->length; if (EVP_DecodeUpdate(ctx, (unsigned char*)buf_mem->data, &len, (unsigned char*)buf_mem->data, len) < 0 || EVP_DecodeFinal(ctx, (unsigned char*)&(buf_mem->data[len]), &taillen) < 0) { PEMerr(PEM_F_PEM_READ_BIO_EX, PEM_R_BAD_BASE64_DECODE); goto end; } len += taillen; buf_mem->length = len; /* There was no data in the PEM file; avoid malloc(0). */ if (len == 0) goto end; headerlen = BIO_get_mem_data(headerB, NULL); *header = pem_malloc(headerlen + 1, flags); *data = pem_malloc(len, flags); if (*header == NULL || *data == NULL) { pem_free(*header, flags, 0); pem_free(*data, flags, 0); goto end; } BIO_read(headerB, *header, headerlen); (*header)[headerlen] = '\0'; BIO_read(dataB, *data, len); *len_out = len; *name_out = name; name = NULL; ret = 1; end: EVP_ENCODE_CTX_free(ctx); pem_free(name, flags, 0); BIO_free(headerB); BIO_free(dataB); return ret; }
/** * Extract the optional PEM header, with details on the type of content and * any encryption used on the contents, and the bulk of the data from the bio. * The end of the header is marked by a blank line; if the end-of-input marker * is reached prior to a blank line, there is no header. * * The header and data arguments are BIO** since we may have to swap them * if there is no header, for efficiency. * * We need the name of the PEM-encoded type to verify the end string. */ static int get_header_and_data(BIO *bp, BIO **header, BIO **data, char *name, unsigned int flags) { BIO *tmp = *header; char *linebuf, *p; int len, line, ret = 0, end = 0; /* 0 if not seen (yet), 1 if reading header, 2 if finished header */ enum header_status got_header = MAYBE_HEADER; unsigned int flags_mask; size_t namelen; /* Need to hold trailing NUL (accounted for by BIO_gets() and the newline * that will be added by sanitize_line() (the extra '1'). */ linebuf = pem_malloc(LINESIZE + 1, flags); if (linebuf == NULL) { PEMerr(PEM_F_GET_HEADER_AND_DATA, ERR_R_MALLOC_FAILURE); return 0; } for (line = 0; ; line++) { flags_mask = ~0u; len = BIO_gets(bp, linebuf, LINESIZE); if (len <= 0) { PEMerr(PEM_F_GET_HEADER_AND_DATA, PEM_R_SHORT_HEADER); goto err; } if (got_header == MAYBE_HEADER) { if (memchr(linebuf, ':', len) != NULL) got_header = IN_HEADER; } if (!strncmp(linebuf, endstr, ENDLEN) || got_header == IN_HEADER) flags_mask &= ~PEM_FLAG_ONLY_B64; len = sanitize_line(linebuf, len, flags & flags_mask); /* Check for end of header. */ if (linebuf[0] == '\n') { if (got_header == POST_HEADER) { /* Another blank line is an error. */ PEMerr(PEM_F_GET_HEADER_AND_DATA, PEM_R_BAD_END_LINE); goto err; } got_header = POST_HEADER; tmp = *data; continue; } /* Check for end of stream (which means there is no header). */ if (strncmp(linebuf, endstr, ENDLEN) == 0) { p = linebuf + ENDLEN; namelen = strlen(name); if (strncmp(p, name, namelen) != 0 || strncmp(p + namelen, tailstr, TAILLEN) != 0) { PEMerr(PEM_F_GET_HEADER_AND_DATA, PEM_R_BAD_END_LINE); goto err; } if (got_header == MAYBE_HEADER) { *header = *data; *data = tmp; } break; } else if (end) { /* Malformed input; short line not at end of data. */ PEMerr(PEM_F_GET_HEADER_AND_DATA, PEM_R_BAD_END_LINE); goto err; } /* * Else, a line of text -- could be header or data; we don't * know yet. Just pass it through. */ if (BIO_puts(tmp, linebuf) < 0) goto err; /* * Only encrypted files need the line length check applied. */ if (got_header == POST_HEADER) { /* 65 includes the trailing newline */ if (len > 65) goto err; if (len < 65) end = 1; } } ret = 1; err: pem_free(linebuf, flags, LINESIZE + 1); return ret; }
/* * Parse a CSR */ int x509_csr_parse( x509_csr *csr, const unsigned char *buf, size_t buflen ) { int ret; size_t len; unsigned char *p, *end; #if defined(POLARSSL_PEM_PARSE_C) size_t use_len; pem_context pem; #endif /* * Check for valid input */ if( csr == NULL || buf == NULL ) return( POLARSSL_ERR_X509_BAD_INPUT_DATA ); x509_csr_init( csr ); #if defined(POLARSSL_PEM_PARSE_C) pem_init( &pem ); ret = pem_read_buffer( &pem, "-----BEGIN CERTIFICATE REQUEST-----", "-----END CERTIFICATE REQUEST-----", buf, NULL, 0, &use_len ); if( ret == 0 ) { /* * Was PEM encoded */ buflen -= use_len; buf += use_len; /* * Steal PEM buffer */ p = pem.buf; pem.buf = NULL; len = pem.buflen; pem_free( &pem ); } else if( ret != POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) { pem_free( &pem ); return( ret ); } else #endif { /* * nope, copy the raw DER data */ p = (unsigned char *) polarssl_malloc( len = buflen ); if( p == NULL ) return( POLARSSL_ERR_X509_MALLOC_FAILED ); memcpy( p, buf, buflen ); buflen = 0; } csr->raw.p = p; csr->raw.len = len; end = p + len; /* * CertificationRequest ::= SEQUENCE { * certificationRequestInfo CertificationRequestInfo, * signatureAlgorithm AlgorithmIdentifier, * signature BIT STRING * } */ if( ( ret = asn1_get_tag( &p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) { x509_csr_free( csr ); return( POLARSSL_ERR_X509_INVALID_FORMAT ); } if( len != (size_t) ( end - p ) ) { x509_csr_free( csr ); return( POLARSSL_ERR_X509_INVALID_FORMAT + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); } /* * CertificationRequestInfo ::= SEQUENCE { */ csr->cri.p = p; if( ( ret = asn1_get_tag( &p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) { x509_csr_free( csr ); return( POLARSSL_ERR_X509_INVALID_FORMAT + ret ); } end = p + len; csr->cri.len = end - csr->cri.p; /* * Version ::= INTEGER { v1(0) } */ if( ( ret = x509_csr_get_version( &p, end, &csr->version ) ) != 0 ) { x509_csr_free( csr ); return( ret ); } csr->version++; if( csr->version != 1 ) { x509_csr_free( csr ); return( POLARSSL_ERR_X509_UNKNOWN_VERSION ); } /* * subject Name */ csr->subject_raw.p = p; if( ( ret = asn1_get_tag( &p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) { x509_csr_free( csr ); return( POLARSSL_ERR_X509_INVALID_FORMAT + ret ); } if( ( ret = x509_get_name( &p, p + len, &csr->subject ) ) != 0 ) { x509_csr_free( csr ); return( ret ); } csr->subject_raw.len = p - csr->subject_raw.p; /* * subjectPKInfo SubjectPublicKeyInfo */ if( ( ret = pk_parse_subpubkey( &p, end, &csr->pk ) ) != 0 ) { x509_csr_free( csr ); return( ret ); } /* * attributes [0] Attributes */ if( ( ret = asn1_get_tag( &p, end, &len, ASN1_CONSTRUCTED | ASN1_CONTEXT_SPECIFIC ) ) != 0 ) { x509_csr_free( csr ); return( POLARSSL_ERR_X509_INVALID_FORMAT + ret ); } // TODO Parse Attributes / extension requests p += len; end = csr->raw.p + csr->raw.len; /* * signatureAlgorithm AlgorithmIdentifier, * signature BIT STRING */ if( ( ret = x509_get_alg_null( &p, end, &csr->sig_oid ) ) != 0 ) { x509_csr_free( csr ); return( ret ); } if( ( ret = x509_get_sig_alg( &csr->sig_oid, &csr->sig_md, &csr->sig_pk ) ) != 0 ) { x509_csr_free( csr ); return( POLARSSL_ERR_X509_UNKNOWN_SIG_ALG ); } if( ( ret = x509_get_sig( &p, end, &csr->sig ) ) != 0 ) { x509_csr_free( csr ); return( ret ); } if( p != end ) { x509_csr_free( csr ); return( POLARSSL_ERR_X509_INVALID_FORMAT + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); } return( 0 ); }
/* * Parse a private key */ int pk_parse_key( pk_context *pk, const unsigned char *key, size_t keylen, const unsigned char *pwd, size_t pwdlen ) { int ret; const pk_info_t *pk_info; #if defined(POLARSSL_PEM_PARSE_C) size_t len; pem_context pem; pem_init( &pem ); #if defined(POLARSSL_RSA_C) ret = pem_read_buffer( &pem, "-----BEGIN RSA PRIVATE KEY-----", "-----END RSA PRIVATE KEY-----", key, pwd, pwdlen, &len ); if( ret == 0 ) { if( ( pk_info = pk_info_from_type( POLARSSL_PK_RSA ) ) == NULL ) return( POLARSSL_ERR_PK_UNKNOWN_PK_ALG ); if( ( ret = pk_init_ctx( pk, pk_info ) ) != 0 || ( ret = pk_parse_key_pkcs1_der( pk_rsa( *pk ), pem.buf, pem.buflen ) ) != 0 ) { pk_free( pk ); } pem_free( &pem ); return( ret ); } else if( ret == POLARSSL_ERR_PEM_PASSWORD_MISMATCH ) return( POLARSSL_ERR_PK_PASSWORD_MISMATCH ); else if( ret == POLARSSL_ERR_PEM_PASSWORD_REQUIRED ) return( POLARSSL_ERR_PK_PASSWORD_REQUIRED ); else if( ret != POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) return( ret ); #endif /* POLARSSL_RSA_C */ #if defined(POLARSSL_ECP_C) ret = pem_read_buffer( &pem, "-----BEGIN EC PRIVATE KEY-----", "-----END EC PRIVATE KEY-----", key, pwd, pwdlen, &len ); if( ret == 0 ) { if( ( pk_info = pk_info_from_type( POLARSSL_PK_ECKEY ) ) == NULL ) return( POLARSSL_ERR_PK_UNKNOWN_PK_ALG ); if( ( ret = pk_init_ctx( pk, pk_info ) ) != 0 || ( ret = pk_parse_key_sec1_der( pk_ec( *pk ), pem.buf, pem.buflen ) ) != 0 ) { pk_free( pk ); } pem_free( &pem ); return( ret ); } else if( ret == POLARSSL_ERR_PEM_PASSWORD_MISMATCH ) return( POLARSSL_ERR_PK_PASSWORD_MISMATCH ); else if( ret == POLARSSL_ERR_PEM_PASSWORD_REQUIRED ) return( POLARSSL_ERR_PK_PASSWORD_REQUIRED ); else if( ret != POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) return( ret ); #endif /* POLARSSL_ECP_C */ ret = pem_read_buffer( &pem, "-----BEGIN PRIVATE KEY-----", "-----END PRIVATE KEY-----", key, NULL, 0, &len ); if( ret == 0 ) { if( ( ret = pk_parse_key_pkcs8_unencrypted_der( pk, pem.buf, pem.buflen ) ) != 0 ) { pk_free( pk ); } pem_free( &pem ); return( ret ); } else if( ret != POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) return( ret ); #if defined(POLARSSL_PKCS12_C) || defined(POLARSSL_PKCS5_C) ret = pem_read_buffer( &pem, "-----BEGIN ENCRYPTED PRIVATE KEY-----", "-----END ENCRYPTED PRIVATE KEY-----", key, NULL, 0, &len ); if( ret == 0 ) { if( ( ret = pk_parse_key_pkcs8_encrypted_der( pk, pem.buf, pem.buflen, pwd, pwdlen ) ) != 0 ) { pk_free( pk ); } pem_free( &pem ); return( ret ); } else if( ret != POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) return( ret ); #endif /* POLARSSL_PKCS12_C || POLARSSL_PKCS5_C */ #else ((void) pwd); ((void) pwdlen); #endif /* POLARSSL_PEM_PARSE_C */ /* * At this point we only know it's not a PEM formatted key. Could be any * of the known DER encoded private key formats * * We try the different DER format parsers to see if one passes without * error */ #if defined(POLARSSL_PKCS12_C) || defined(POLARSSL_PKCS5_C) if( ( ret = pk_parse_key_pkcs8_encrypted_der( pk, key, keylen, pwd, pwdlen ) ) == 0 ) { return( 0 ); } pk_free( pk ); if( ret == POLARSSL_ERR_PK_PASSWORD_MISMATCH ) { return( ret ); } #endif /* POLARSSL_PKCS12_C || POLARSSL_PKCS5_C */ if( ( ret = pk_parse_key_pkcs8_unencrypted_der( pk, key, keylen ) ) == 0 ) return( 0 ); pk_free( pk ); #if defined(POLARSSL_RSA_C) if( ( pk_info = pk_info_from_type( POLARSSL_PK_RSA ) ) == NULL ) return( POLARSSL_ERR_PK_UNKNOWN_PK_ALG ); if( ( ret = pk_init_ctx( pk, pk_info ) ) != 0 || ( ret = pk_parse_key_pkcs1_der( pk_rsa( *pk ), key, keylen ) ) == 0 ) { return( 0 ); } pk_free( pk ); #endif /* POLARSSL_RSA_C */ #if defined(POLARSSL_ECP_C) if( ( pk_info = pk_info_from_type( POLARSSL_PK_ECKEY ) ) == NULL ) return( POLARSSL_ERR_PK_UNKNOWN_PK_ALG ); if( ( ret = pk_init_ctx( pk, pk_info ) ) != 0 || ( ret = pk_parse_key_sec1_der( pk_ec( *pk ), key, keylen ) ) == 0 ) { return( 0 ); } pk_free( pk ); #endif /* POLARSSL_ECP_C */ return( POLARSSL_ERR_PK_KEY_INVALID_FORMAT ); }
/* * Parse one or more PEM certificates from a buffer and add them to the chained list */ int x509_crt_parse( x509_crt *chain, const unsigned char *buf, size_t buflen ) { int success = 0, first_error = 0, total_failed = 0; int buf_format = X509_FORMAT_DER; /* * Check for valid input */ if( chain == NULL || buf == NULL ) return( POLARSSL_ERR_X509_BAD_INPUT_DATA ); /* * Determine buffer content. Buffer contains either one DER certificate or * one or more PEM certificates. */ #if defined(POLARSSL_PEM_PARSE_C) if( strstr( (const char *) buf, "-----BEGIN CERTIFICATE-----" ) != NULL ) buf_format = X509_FORMAT_PEM; #endif if( buf_format == X509_FORMAT_DER ) return x509_crt_parse_der( chain, buf, buflen ); #if defined(POLARSSL_PEM_PARSE_C) if( buf_format == X509_FORMAT_PEM ) { int ret; pem_context pem; while( buflen > 0 ) { size_t use_len; pem_init( &pem ); ret = pem_read_buffer( &pem, "-----BEGIN CERTIFICATE-----", "-----END CERTIFICATE-----", buf, NULL, 0, &use_len ); if( ret == 0 ) { /* * Was PEM encoded */ buflen -= use_len; buf += use_len; } else if( ret == POLARSSL_ERR_PEM_BAD_INPUT_DATA ) { return( ret ); } else if( ret != POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) { pem_free( &pem ); /* * PEM header and footer were found */ buflen -= use_len; buf += use_len; if( first_error == 0 ) first_error = ret; continue; } else break; ret = x509_crt_parse_der( chain, pem.buf, pem.buflen ); pem_free( &pem ); if( ret != 0 ) { /* * Quit parsing on a memory error */ if( ret == POLARSSL_ERR_X509_MALLOC_FAILED ) return( ret ); if( first_error == 0 ) first_error = ret; total_failed++; continue; } success = 1; } } #endif if( success ) return( total_failed ); else if( first_error ) return( first_error ); else return( POLARSSL_ERR_X509_CERT_UNKNOWN_FORMAT ); }
/* * Parse one or more CRLs and add them to the chained list */ int x509_crl_parse( x509_crl *chain, const unsigned char *buf, size_t buflen ) { int ret; size_t len; unsigned char *p, *end; x509_crl *crl; #if defined(POLARSSL_PEM_PARSE_C) size_t use_len; pem_context pem; #endif crl = chain; /* * Check for valid input */ if( crl == NULL || buf == NULL ) return( POLARSSL_ERR_X509_BAD_INPUT_DATA ); while( crl->version != 0 && crl->next != NULL ) crl = crl->next; /* * Add new CRL on the end of the chain if needed. */ if ( crl->version != 0 && crl->next == NULL) { crl->next = (x509_crl *) polarssl_malloc( sizeof( x509_crl ) ); if( crl->next == NULL ) { x509_crl_free( crl ); return( POLARSSL_ERR_X509_MALLOC_FAILED ); } crl = crl->next; x509_crl_init( crl ); } #if defined(POLARSSL_PEM_PARSE_C) pem_init( &pem ); ret = pem_read_buffer( &pem, "-----BEGIN X509 CRL-----", "-----END X509 CRL-----", buf, NULL, 0, &use_len ); if( ret == 0 ) { /* * Was PEM encoded */ buflen -= use_len; buf += use_len; /* * Steal PEM buffer */ p = pem.buf; pem.buf = NULL; len = pem.buflen; pem_free( &pem ); } else if( ret != POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) { pem_free( &pem ); return( ret ); } else #endif { /* * nope, copy the raw DER data */ p = (unsigned char *) polarssl_malloc( len = buflen ); if( p == NULL ) return( POLARSSL_ERR_X509_MALLOC_FAILED ); memcpy( p, buf, buflen ); buflen = 0; } crl->raw.p = p; crl->raw.len = len; end = p + len; /* * CertificateList ::= SEQUENCE { * tbsCertList TBSCertList, * signatureAlgorithm AlgorithmIdentifier, * signatureValue BIT STRING } */ if( ( ret = asn1_get_tag( &p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) { x509_crl_free( crl ); return( POLARSSL_ERR_X509_INVALID_FORMAT ); } if( len != (size_t) ( end - p ) ) { x509_crl_free( crl ); return( POLARSSL_ERR_X509_INVALID_FORMAT + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); } /* * TBSCertList ::= SEQUENCE { */ crl->tbs.p = p; if( ( ret = asn1_get_tag( &p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) { x509_crl_free( crl ); return( POLARSSL_ERR_X509_INVALID_FORMAT + ret ); } end = p + len; crl->tbs.len = end - crl->tbs.p; /* * Version ::= INTEGER OPTIONAL { v1(0), v2(1) } * -- if present, MUST be v2 * * signature AlgorithmIdentifier */ if( ( ret = x509_crl_get_version( &p, end, &crl->version ) ) != 0 || ( ret = x509_get_alg_null( &p, end, &crl->sig_oid1 ) ) != 0 ) { x509_crl_free( crl ); return( ret ); } crl->version++; if( crl->version > 2 ) { x509_crl_free( crl ); return( POLARSSL_ERR_X509_UNKNOWN_VERSION ); } if( ( ret = x509_get_sig_alg( &crl->sig_oid1, &crl->sig_md, &crl->sig_pk ) ) != 0 ) { x509_crl_free( crl ); return( POLARSSL_ERR_X509_UNKNOWN_SIG_ALG ); } /* * issuer Name */ crl->issuer_raw.p = p; if( ( ret = asn1_get_tag( &p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) { x509_crl_free( crl ); return( POLARSSL_ERR_X509_INVALID_FORMAT + ret ); } if( ( ret = x509_get_name( &p, p + len, &crl->issuer ) ) != 0 ) { x509_crl_free( crl ); return( ret ); } crl->issuer_raw.len = p - crl->issuer_raw.p; /* * thisUpdate Time * nextUpdate Time OPTIONAL */ if( ( ret = x509_get_time( &p, end, &crl->this_update ) ) != 0 ) { x509_crl_free( crl ); return( ret ); } if( ( ret = x509_get_time( &p, end, &crl->next_update ) ) != 0 ) { if ( ret != ( POLARSSL_ERR_X509_INVALID_DATE + POLARSSL_ERR_ASN1_UNEXPECTED_TAG ) && ret != ( POLARSSL_ERR_X509_INVALID_DATE + POLARSSL_ERR_ASN1_OUT_OF_DATA ) ) { x509_crl_free( crl ); return( ret ); } } /* * revokedCertificates SEQUENCE OF SEQUENCE { * userCertificate CertificateSerialNumber, * revocationDate Time, * crlEntryExtensions Extensions OPTIONAL * -- if present, MUST be v2 * } OPTIONAL */ if( ( ret = x509_get_entries( &p, end, &crl->entry ) ) != 0 ) { x509_crl_free( crl ); return( ret ); } /* * crlExtensions EXPLICIT Extensions OPTIONAL * -- if present, MUST be v2 */ if( crl->version == 2 ) { ret = x509_get_crl_ext( &p, end, &crl->crl_ext ); if( ret != 0 ) { x509_crl_free( crl ); return( ret ); } } if( p != end ) { x509_crl_free( crl ); return( POLARSSL_ERR_X509_INVALID_FORMAT + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); } end = crl->raw.p + crl->raw.len; /* * signatureAlgorithm AlgorithmIdentifier, * signatureValue BIT STRING */ if( ( ret = x509_get_alg_null( &p, end, &crl->sig_oid2 ) ) != 0 ) { x509_crl_free( crl ); return( ret ); } if( crl->sig_oid1.len != crl->sig_oid2.len || memcmp( crl->sig_oid1.p, crl->sig_oid2.p, crl->sig_oid1.len ) != 0 ) { x509_crl_free( crl ); return( POLARSSL_ERR_X509_SIG_MISMATCH ); } if( ( ret = x509_get_sig( &p, end, &crl->sig ) ) != 0 ) { x509_crl_free( crl ); return( ret ); } if( p != end ) { x509_crl_free( crl ); return( POLARSSL_ERR_X509_INVALID_FORMAT + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); } if( buflen > 0 ) { crl->next = (x509_crl *) polarssl_malloc( sizeof( x509_crl ) ); if( crl->next == NULL ) { x509_crl_free( crl ); return( POLARSSL_ERR_X509_MALLOC_FAILED ); } crl = crl->next; x509_crl_init( crl ); return( x509_crl_parse( crl, buf, buflen ) ); } return( 0 ); }