Example #1
0
/*
 * Parse one or more certificates and add them to the chain
 */
int x509_add_certs( x509_cert *chain, unsigned char *buf, int buflen )
{
    int ret, len;
    unsigned char *s1, *s2;
    unsigned char *p, *end;
    x509_cert *crt;

    crt = chain;

    while( crt->version != 0 )
        crt = crt->next;

    /*
     * check if the certificate is encoded in base64
     */
    s1 = (unsigned char *) strstr( (char *) buf,
        "-----BEGIN CERTIFICATE-----" );

    if( s1 != NULL )
    {
        s2 = (unsigned char *) strstr( (char *) buf,
            "-----END CERTIFICATE-----" );

        if( s2 == NULL || s2 <= s1 )
            return( ERR_X509_CERT_INVALID_PEM );

        s1 += 27;
        if( *s1 == '\r' ) s1++;
        if( *s1 == '\n' ) s1++;
            else return( ERR_X509_CERT_INVALID_PEM );

        /*
         * get the DER data length and decode the buffer
         */
        len = 0;
        ret = base64_decode( NULL, &len, s1, s2 - s1 );

        if( ret == ERR_BASE64_INVALID_CHARACTER )
            return( ERR_X509_CERT_INVALID_PEM | ret );

        if( ( p = (unsigned char *) malloc( len ) ) == NULL )
            return( 1 );
            
        if( ( ret = base64_decode( p, &len, s1, s2 - s1 ) ) != 0 )
        {
            free( p );
            return( ERR_X509_CERT_INVALID_PEM | ret );
        }

        /*
         * update the buffer size and offset
         */
        s2 += 25;
        if( *s2 == '\r' ) s2++;
        if( *s2 == '\n' ) s2++;
            else return( ERR_X509_CERT_INVALID_PEM );

        buflen -= s2 - buf;
        buf = s2;
    }
    else
    {
        /*
         * nope, copy the raw DER data
         */
        p = (unsigned char *) malloc( len = buflen );

        if( p == NULL )
            return( 1 );

        memcpy( p, buf, buflen );

        buflen = 0;
    }

    crt->raw.p = p;
    crt->raw.len = len;
    end = p + len;

    /*
     * Certificate  ::=  SEQUENCE  {
     *      tbsCertificate       TBSCertificate,
     *      signatureAlgorithm   AlgorithmIdentifier,
     *      signatureValue       BIT STRING  }
     */
    if( ( ret = asn1_get_tag( &p, end, &len,
            ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
    {
        x509_free_cert( crt );
        return( ERR_X509_CERT_INVALID_FORMAT );
    }

    if( len != (int) ( end - p ) )
    {
        x509_free_cert( crt );
        return( ERR_X509_CERT_INVALID_FORMAT |
                ERR_ASN1_LENGTH_MISMATCH );
    }

    /*
     * TBSCertificate  ::=  SEQUENCE  {
     */
    crt->tbs.p = p;

    if( ( ret = asn1_get_tag( &p, end, &len,
            ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
    {
        x509_free_cert( crt );
        return( ERR_X509_CERT_INVALID_FORMAT | ret );
    }

    end = p + len;
    crt->tbs.len = end - crt->tbs.p;

    /*
     * Version  ::=  INTEGER  {  v1(0), v2(1), v3(2)  }
     *
     * CertificateSerialNumber  ::=  INTEGER
     *
     * signature            AlgorithmIdentifier
     */
    if( ( ret = x509_get_version( &p, end, &crt->version ) ) != 0 ||
        ( ret = x509_get_serial(  &p, end, &crt->serial  ) ) != 0 ||
        ( ret = x509_get_alg(  &p, end, &crt->sig_oid1   ) ) != 0 )
    {
        x509_free_cert( crt );
        return( ret );
    }

    crt->version++;

    if( crt->version > 3 )
    {
        x509_free_cert( crt );
        return( ERR_X509_CERT_UNKNOWN_VERSION );
    }

    if( crt->sig_oid1.len != 9 ||
        memcmp( crt->sig_oid1.p, OID_PKCS1, 8 ) != 0 )
    {
        x509_free_cert( crt );
        return( ERR_X509_CERT_UNKNOWN_SIG_ALG );
    }

    if( crt->sig_oid1.p[8] < 2 ||
        crt->sig_oid1.p[8] > 5 )
    {
        x509_free_cert( crt );
        return( ERR_X509_CERT_UNKNOWN_SIG_ALG );
    }

    /*
     * issuer               Name
     */
    crt->issuer_raw.p = p;

    if( ( ret = asn1_get_tag( &p, end, &len,
            ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
    {
        x509_free_cert( crt );
        return( ERR_X509_CERT_INVALID_FORMAT | ret );
    }

    if( ( ret = x509_get_name( &p, p + len, &crt->issuer ) ) != 0 )
    {
        x509_free_cert( crt );
        return( ret );
    }

    crt->issuer_raw.len = p - crt->issuer_raw.p;

    /*
     * Validity ::= SEQUENCE {
     *      notBefore      Time,
     *      notAfter       Time }
     *
     */
    if( ( ret = x509_get_dates( &p, end, &crt->valid_from,
                                         &crt->valid_to ) ) != 0 )
    {
        x509_free_cert( crt );
        return( ret );
    }

    /*
     * subject              Name
     */
    crt->subject_raw.p = p;

    if( ( ret = asn1_get_tag( &p, end, &len,
            ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
    {
        x509_free_cert( crt );
        return( ERR_X509_CERT_INVALID_FORMAT | ret );
    }

    if( ( ret = x509_get_name( &p, p + len, &crt->subject ) ) != 0 )
    {
        x509_free_cert( crt );
        return( ret );
    }

    crt->subject_raw.len = p - crt->subject_raw.p;

    /*
     * SubjectPublicKeyInfo  ::=  SEQUENCE
     *      algorithm            AlgorithmIdentifier,
     *      subjectPublicKey     BIT STRING  }
     */
    if( ( ret = asn1_get_tag( &p, end, &len,
            ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
    {
        x509_free_cert( crt );
        return( ERR_X509_CERT_INVALID_FORMAT | ret );
    }

    if( ( ret = x509_get_pubkey( &p, p + len, &crt->pk_oid,
                                 &crt->rsa.N, &crt->rsa.E ) ) != 0 )
    {
        x509_free_cert( crt );
        return( ret );
    }

    if( ( ret = rsa_check_pubkey( &crt->rsa ) ) != 0 )
    {
        x509_free_cert( crt );
        return( ret );
    }

    crt->rsa.len = ( mpi_size( &crt->rsa.N ) + 7 ) >> 3;

    /*
     *  issuerUniqueID  [1]  IMPLICIT UniqueIdentifier OPTIONAL,
     *                       -- If present, version shall be v2 or v3
     *  subjectUniqueID [2]  IMPLICIT UniqueIdentifier OPTIONAL,
     *                       -- If present, version shall be v2 or v3
     *  extensions      [3]  EXPLICIT Extensions OPTIONAL
     *                       -- If present, version shall be v3
     */
    if( crt->version == 2 || crt->version == 3 )
    {
        ret = x509_get_uid( &p, end, &crt->issuer_id,  1 );
        if( ret != 0 )
        {
            x509_free_cert( crt );
            return( ret );
        }
    }

    if( crt->version == 2 || crt->version == 3 )
    {
        ret = x509_get_uid( &p, end, &crt->subject_id,  2 );
        if( ret != 0 )
        {
            x509_free_cert( crt );
            return( ret );
        }
    }

    if( crt->version == 3 )
    {
        ret = x509_get_ext( &p, end, &crt->v3_ext,
                            &crt->ca_istrue, &crt->max_pathlen );
        if( ret != 0 )
        {
            x509_free_cert( crt );
            return( ret );
        }
    }

    if( p != end )
    {
        x509_free_cert( crt );
        return( ERR_X509_CERT_INVALID_FORMAT |
                ERR_ASN1_LENGTH_MISMATCH );
    }

    end = crt->raw.p + crt->raw.len;

    /*
     *  signatureAlgorithm   AlgorithmIdentifier,
     *  signatureValue       BIT STRING
     */
    if( ( ret = x509_get_alg( &p, end, &crt->sig_oid2 ) ) != 0 )
    {
        x509_free_cert( crt );
        return( ret );
    }

    if( memcmp( crt->sig_oid1.p, crt->sig_oid2.p, 9 ) != 0 )
    {
        x509_free_cert( crt );
        return( ERR_X509_CERT_SIG_MISMATCH );
    }

    if( ( ret = x509_get_sig( &p, end, &crt->sig ) ) != 0 )
    {
        x509_free_cert( crt );
        return( ret );
    }

    if( p != end )
    {
        x509_free_cert( crt );
        return( ERR_X509_CERT_INVALID_FORMAT |
                ERR_ASN1_LENGTH_MISMATCH );
    }

    crt->next = (x509_cert *) malloc( sizeof( x509_cert ) );

    if( crt->next == NULL )
    {
        x509_free_cert( crt );
        return( 1 );
    }

    crt = crt->next;
    memset( crt, 0, sizeof( x509_cert ) );

    if( buflen > 0 )
        return( x509_add_certs( crt, buf, buflen ) );

    return( 0 );
}
Example #2
0
/**
 * Parse and fill a single X.509 certificate in DER format.
 */
static int
x509_crt_parse_der_core(ttls_x509_crt *crt, unsigned char *buf, size_t buflen)
{
	int r;
	size_t len;
	unsigned char *p, *end, *crt_end;
	ttls_x509_buf sig_params1, sig_params2, sig_oid2;

	BUG_ON(!crt || !buf);
	memset(&sig_params1, 0, sizeof(ttls_x509_buf));
	memset(&sig_params2, 0, sizeof(ttls_x509_buf));
	memset(&sig_oid2, 0, sizeof(ttls_x509_buf));

	p = (unsigned char*)buf;
	len = buflen;
	end = p + len;

	/*
	 * Certificate  ::=  SEQUENCE  {
	 *   tbsCertificate		TBSCertificate,
	 *   signatureAlgorithm		AlgorithmIdentifier,
	 *   signatureValue		BIT STRING
	 * }
	 */
	r = ttls_asn1_get_tag(&p, end, &len,
			      TTLS_ASN1_CONSTRUCTED | TTLS_ASN1_SEQUENCE);
	if (r) {
		ttls_x509_crt_free(crt);
		return TTLS_ERR_X509_INVALID_FORMAT;
	}
	if (len > (size_t)(end - p)) {
		ttls_x509_crt_free(crt);
		return TTLS_ERR_X509_INVALID_FORMAT
			+ TTLS_ERR_ASN1_LENGTH_MISMATCH;
	}
	crt_end = p + len;

	/*
	 * Create and populate a new buffer for the raw field.
	 * Reuse the buffer, we're responsible to free the pages later.
	 */
	crt->raw.len = crt_end - buf;
	crt->raw.p = p = buf;

	/* Direct pointers to the new buffer. */
	p += crt->raw.len - len;
	end = crt_end = p + len;

	/* TBSCertificate  ::=  SEQUENCE  { */
	crt->tbs.p = p;

	r = ttls_asn1_get_tag(&p, end, &len,
			      TTLS_ASN1_CONSTRUCTED | TTLS_ASN1_SEQUENCE);
	if (r) {
		ttls_x509_crt_free(crt);
		return TTLS_ERR_X509_INVALID_FORMAT + r;
	}

	end = p + len;
	crt->tbs.len = end - crt->tbs.p;

	/*
	 * Version ::= INTEGER { v1(0), v2(1), v3(2) }
	 *
	 * CertificateSerialNumber ::= INTEGER
	 *
	 * signature AlgorithmIdentifier
	 */
	if ((r = x509_get_version( &p, end, &crt->version ))
	    || (r = ttls_x509_get_serial(&p, end, &crt->serial))
	    || (r = ttls_x509_get_alg(&p, end, &crt->sig_oid, &sig_params1)))
	{
		ttls_x509_crt_free(crt);
		return r;
	}
	if (crt->version < 0 || crt->version > 2) {
		ttls_x509_crt_free(crt);
		return TTLS_ERR_X509_UNKNOWN_VERSION;
	}
	crt->version++;

	r = ttls_x509_get_sig_alg(&crt->sig_oid, &sig_params1, &crt->sig_md,
				  &crt->sig_pk, &crt->sig_opts);
	if (r) {
		ttls_x509_crt_free(crt);
		return r;
	}

	/* issuer Name */
	crt->issuer_raw.p = p;

	r = ttls_asn1_get_tag(&p, end, &len,
			      TTLS_ASN1_CONSTRUCTED | TTLS_ASN1_SEQUENCE);
	if (r) {
		ttls_x509_crt_free(crt);
		return TTLS_ERR_X509_INVALID_FORMAT + r;
	}
	if ((r = ttls_x509_get_name(&p, p + len, &crt->issuer))) {
		ttls_x509_crt_free(crt);
		return r;
	}
	crt->issuer_raw.len = p - crt->issuer_raw.p;

	/*
	 * Validity ::= SEQUENCE {
	 *	notBefore	Time,
	 *	notAfter	Time
	 * }
	 */
	r = x509_get_dates(&p, end, &crt->valid_from, &crt->valid_to);
	if (r) {
		ttls_x509_crt_free(crt);
		return r;
	}

	/* subject Name */
	crt->subject_raw.p = p;
	r = ttls_asn1_get_tag(&p, end, &len,
			      TTLS_ASN1_CONSTRUCTED | TTLS_ASN1_SEQUENCE);
	if (r) {
		ttls_x509_crt_free(crt);
		return TTLS_ERR_X509_INVALID_FORMAT + r;
	}
	if (len && (r = ttls_x509_get_name(&p, p + len, &crt->subject))) {
		ttls_x509_crt_free(crt);
		return r;
	}
	crt->subject_raw.len = p - crt->subject_raw.p;

	/* SubjectPublicKeyInfo */
	if ((r = ttls_pk_parse_subpubkey(&p, end, &crt->pk))) {
		ttls_x509_crt_free(crt);
		return r;
	}

	/*
	 *  issuerUniqueID  [1] IMPLICIT UniqueIdentifier OPTIONAL,
	 *		-- If present, version shall be v2 or v3
	 *  subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
	 *		-- If present, version shall be v2 or v3
	 *  extensions      [3] EXPLICIT Extensions OPTIONAL
	 *		-- If present, version shall be v3
	 */
	if (crt->version == 2 || crt->version == 3) {
		if ((r = x509_get_uid(&p, end, &crt->issuer_id, 1))) {
			ttls_x509_crt_free(crt);
			return r;
		}
		if ((r = x509_get_uid(&p, end, &crt->subject_id,  2))) {
			ttls_x509_crt_free(crt);
			return r;
		}
	}
	if (crt->version == 3) {
		if ((r = x509_get_crt_ext(&p, end, crt))) {
			ttls_x509_crt_free(crt);
			return r;
		}
	}

	if (p != end) {
		ttls_x509_crt_free(crt);
		return TTLS_ERR_X509_INVALID_FORMAT
			+ TTLS_ERR_ASN1_LENGTH_MISMATCH;
	}
	end = crt_end;

	/*
	 * }
	 * -- end of TBSCertificate
	 *
	 * signatureAlgorithm	AlgorithmIdentifier,
	 * signatureValue	BIT STRING
	 */
	if ((r = ttls_x509_get_alg(&p, end, &sig_oid2, &sig_params2))) {
		ttls_x509_crt_free(crt);
		return r;
	}
	if (crt->sig_oid.len != sig_oid2.len
	    || memcmp(crt->sig_oid.p, sig_oid2.p, crt->sig_oid.len)
	    || sig_params1.len != sig_params2.len
	    || (sig_params1.len
		&& memcmp(sig_params1.p, sig_params2.p, sig_params1.len)))
	{
		ttls_x509_crt_free(crt);
		return TTLS_ERR_X509_SIG_MISMATCH;
	}
	if ((r = ttls_x509_get_sig(&p, end, &crt->sig))) {
		ttls_x509_crt_free(crt);
		return r;
	}

	if (p != end) {
		ttls_x509_crt_free(crt);
		return TTLS_ERR_X509_INVALID_FORMAT
			+ TTLS_ERR_ASN1_LENGTH_MISMATCH;
	}

	return 0;
}
Example #3
0
/*
 * Parse and fill a single X.509 certificate in DER format
 */
static int x509_crt_parse_der_core( x509_crt *crt, const unsigned char *buf,
                                    size_t buflen )
{
    int ret;
    size_t len;
    unsigned char *p, *end, *crt_end;

    /*
     * Check for valid input
     */
    if( crt == NULL || buf == NULL )
        return( POLARSSL_ERR_X509_BAD_INPUT_DATA );

    p = (unsigned char *) polarssl_malloc( len = buflen );

    if( p == NULL )
        return( POLARSSL_ERR_X509_MALLOC_FAILED );

    memcpy( p, buf, buflen );

    crt->raw.p = p;
    crt->raw.len = len;
    end = p + len;

    /*
     * Certificate  ::=  SEQUENCE  {
     *      tbsCertificate       TBSCertificate,
     *      signatureAlgorithm   AlgorithmIdentifier,
     *      signatureValue       BIT STRING  }
     */
    if( ( ret = asn1_get_tag( &p, end, &len,
            ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
    {
        x509_crt_free( crt );
        return( POLARSSL_ERR_X509_INVALID_FORMAT );
    }

    if( len > (size_t) ( end - p ) )
    {
        x509_crt_free( crt );
        return( POLARSSL_ERR_X509_INVALID_FORMAT +
                POLARSSL_ERR_ASN1_LENGTH_MISMATCH );
    }
    crt_end = p + len;

    /*
     * TBSCertificate  ::=  SEQUENCE  {
     */
    crt->tbs.p = p;

    if( ( ret = asn1_get_tag( &p, end, &len,
            ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
    {
        x509_crt_free( crt );
        return( POLARSSL_ERR_X509_INVALID_FORMAT + ret );
    }

    end = p + len;
    crt->tbs.len = end - crt->tbs.p;

    /*
     * Version  ::=  INTEGER  {  v1(0), v2(1), v3(2)  }
     *
     * CertificateSerialNumber  ::=  INTEGER
     *
     * signature            AlgorithmIdentifier
     */
    if( ( ret = x509_get_version(  &p, end, &crt->version  ) ) != 0 ||
        ( ret = x509_get_serial(   &p, end, &crt->serial   ) ) != 0 ||
        ( ret = x509_get_alg_null( &p, end, &crt->sig_oid1 ) ) != 0 )
    {
        x509_crt_free( crt );
        return( ret );
    }

    crt->version++;

    if( crt->version > 3 )
    {
        x509_crt_free( crt );
        return( POLARSSL_ERR_X509_UNKNOWN_VERSION );
    }

    if( ( ret = x509_get_sig_alg( &crt->sig_oid1, &crt->sig_md,
                                  &crt->sig_pk ) ) != 0 )
    {
        x509_crt_free( crt );
        return( ret );
    }

    /*
     * issuer               Name
     */
    crt->issuer_raw.p = p;

    if( ( ret = asn1_get_tag( &p, end, &len,
            ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
    {
        x509_crt_free( crt );
        return( POLARSSL_ERR_X509_INVALID_FORMAT + ret );
    }

    if( ( ret = x509_get_name( &p, p + len, &crt->issuer ) ) != 0 )
    {
        x509_crt_free( crt );
        return( ret );
    }

    crt->issuer_raw.len = p - crt->issuer_raw.p;

    /*
     * Validity ::= SEQUENCE {
     *      notBefore      Time,
     *      notAfter       Time }
     *
     */
    if( ( ret = x509_get_dates( &p, end, &crt->valid_from,
                                         &crt->valid_to ) ) != 0 )
    {
        x509_crt_free( crt );
        return( ret );
    }

    /*
     * subject              Name
     */
    crt->subject_raw.p = p;

    if( ( ret = asn1_get_tag( &p, end, &len,
            ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
    {
        x509_crt_free( crt );
        return( POLARSSL_ERR_X509_INVALID_FORMAT + ret );
    }

    if( len && ( ret = x509_get_name( &p, p + len, &crt->subject ) ) != 0 )
    {
        x509_crt_free( crt );
        return( ret );
    }

    crt->subject_raw.len = p - crt->subject_raw.p;

    /*
     * SubjectPublicKeyInfo
     */
    if( ( ret = pk_parse_subpubkey( &p, end, &crt->pk ) ) != 0 )
    {
        x509_crt_free( crt );
        return( ret );
    }

    /*
     *  issuerUniqueID  [1]  IMPLICIT UniqueIdentifier OPTIONAL,
     *                       -- If present, version shall be v2 or v3
     *  subjectUniqueID [2]  IMPLICIT UniqueIdentifier OPTIONAL,
     *                       -- If present, version shall be v2 or v3
     *  extensions      [3]  EXPLICIT Extensions OPTIONAL
     *                       -- If present, version shall be v3
     */
    if( crt->version == 2 || crt->version == 3 )
    {
        ret = x509_get_uid( &p, end, &crt->issuer_id,  1 );
        if( ret != 0 )
        {
            x509_crt_free( crt );
            return( ret );
        }
    }

    if( crt->version == 2 || crt->version == 3 )
    {
        ret = x509_get_uid( &p, end, &crt->subject_id,  2 );
        if( ret != 0 )
        {
            x509_crt_free( crt );
            return( ret );
        }
    }

#if !defined(POLARSSL_X509_ALLOW_EXTENSIONS_NON_V3)
    if( crt->version == 3 )
    {
#endif
        ret = x509_get_crt_ext( &p, end, crt);
        if( ret != 0 )
        {
            x509_crt_free( crt );
            return( ret );
        }
#if !defined(POLARSSL_X509_ALLOW_EXTENSIONS_NON_V3)
    }
#endif

    if( p != end )
    {
        x509_crt_free( crt );
        return( POLARSSL_ERR_X509_INVALID_FORMAT +
                POLARSSL_ERR_ASN1_LENGTH_MISMATCH );
    }

    end = crt_end;

    /*
     *  }
     *  -- end of TBSCertificate
     *
     *  signatureAlgorithm   AlgorithmIdentifier,
     *  signatureValue       BIT STRING
     */
    if( ( ret = x509_get_alg_null( &p, end, &crt->sig_oid2 ) ) != 0 )
    {
        x509_crt_free( crt );
        return( ret );
    }

    if( crt->sig_oid1.len != crt->sig_oid2.len ||
        memcmp( crt->sig_oid1.p, crt->sig_oid2.p, crt->sig_oid1.len ) != 0 )
    {
        x509_crt_free( crt );
        return( POLARSSL_ERR_X509_SIG_MISMATCH );
    }

    if( ( ret = x509_get_sig( &p, end, &crt->sig ) ) != 0 )
    {
        x509_crt_free( crt );
        return( ret );
    }

    if( p != end )
    {
        x509_crt_free( crt );
        return( POLARSSL_ERR_X509_INVALID_FORMAT +
                POLARSSL_ERR_ASN1_LENGTH_MISMATCH );
    }

    return( 0 );
}