Made asn1_get_alg() and asn1_get_alg_null() as generic functions

A generic function for retrieving the AlgorithmIdentifier structure with
its parameters and adapted X509, PKCS#5 and PKCS#12 to use them.
diff --git a/library/asn1parse.c b/library/asn1parse.c
index 2584774..b8823c1 100644
--- a/library/asn1parse.c
+++ b/library/asn1parse.c
@@ -1,7 +1,7 @@
 /*
  *  Generic ASN.1 parsing
  *
- *  Copyright (C) 2006-2011, Brainspark B.V.
+ *  Copyright (C) 2006-2013, Brainspark B.V.
  *
  *  This file is part of PolarSSL (http://www.polarssl.org)
  *  Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
@@ -257,4 +257,63 @@
     return( 0 );
 }
 
+int asn1_get_alg( unsigned char **p,
+                  const unsigned char *end,
+                  asn1_buf *alg, asn1_buf *params )
+{
+    int ret;
+    size_t len;
+
+    if( ( ret = asn1_get_tag( p, end, &len,
+            ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
+        return( ret );
+
+    end = *p + len;
+    alg->tag = **p;
+
+    if( ( ret = asn1_get_tag( p, end, &alg->len, ASN1_OID ) ) != 0 )
+        return( ret );
+
+    alg->p = *p;
+    *p += alg->len;
+
+    if( *p == end )
+    {
+        memset( params, 0, sizeof(asn1_buf) );
+        return( 0 );
+    }
+
+    params->tag = **p;
+    (*p)++;
+
+    if( ( ret = asn1_get_len( p, end, &params->len ) ) != 0 )
+        return( ret );
+
+    params->p = *p;
+    *p += params->len;
+
+    if( *p != end )
+        return( POLARSSL_ERR_ASN1_LENGTH_MISMATCH );
+
+    return( 0 );
+}
+
+int asn1_get_alg_null( unsigned char **p,
+                       const unsigned char *end,
+                       asn1_buf *alg )
+{
+    int ret;
+    asn1_buf params;
+
+    memset( &params, 0, sizeof(asn1_buf) );
+
+    if( ( ret = asn1_get_alg( p, end, alg, &params ) ) != 0 )
+        return( ret );
+
+    if( ( params.tag != ASN1_NULL && params.tag != 0 ) || params.len != 0 )
+        return( POLARSSL_ERR_ASN1_INVALID_DATA );
+
+    return( 0 );
+}
+
 #endif
diff --git a/library/pkcs12.c b/library/pkcs12.c
index 2ee9c5e..6251293 100644
--- a/library/pkcs12.c
+++ b/library/pkcs12.c
@@ -45,12 +45,12 @@
 #include "polarssl/des.h"
 #endif
 
-static int pkcs12_parse_pbe_params( unsigned char **p,
-                                    const unsigned char *end,
+static int pkcs12_parse_pbe_params( asn1_buf *params,
                                     asn1_buf *salt, int *iterations )
 {
     int ret;
-    size_t len = 0;
+    unsigned char **p = &params->p;
+    const unsigned char *end = params->p + params->len;
 
     /*
      *  pkcs-12PbeParams ::= SEQUENCE {
@@ -59,13 +59,9 @@
      *  }
      *
      */
-    if( ( ret = asn1_get_tag( p, end, &len,
-            ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
-    {
-        return( POLARSSL_ERR_PKCS12_PBE_INVALID_FORMAT + ret );
-    }
-
-    end = *p + len;
+    if( params->tag != ( ASN1_CONSTRUCTED | ASN1_SEQUENCE ) )
+        return( POLARSSL_ERR_PKCS12_PBE_INVALID_FORMAT +
+                POLARSSL_ERR_ASN1_UNEXPECTED_TAG );
 
     if( ( ret = asn1_get_tag( p, end, &salt->len, ASN1_OCTET_STRING ) ) != 0 )
         return( POLARSSL_ERR_PKCS12_PBE_INVALID_FORMAT + ret );
@@ -91,16 +87,12 @@
     int ret, iterations;
     asn1_buf salt;
     size_t i;
-    unsigned char *p, *end;
     unsigned char unipwd[258];
 
     memset(&salt, 0, sizeof(asn1_buf));
     memset(&unipwd, 0, sizeof(unipwd));
 
-    p = pbe_params->p;
-    end = p + pbe_params->len;
-
-    if( ( ret = pkcs12_parse_pbe_params( &p, end, &salt, &iterations ) ) != 0 )
+    if( ( ret = pkcs12_parse_pbe_params( pbe_params, &salt, &iterations ) ) != 0 )
         return( ret );
 
     for(i = 0; i < pwdlen; i++)
diff --git a/library/pkcs5.c b/library/pkcs5.c
index c41927b..a363529 100644
--- a/library/pkcs5.c
+++ b/library/pkcs5.c
@@ -42,15 +42,18 @@
 #include "polarssl/cipher.h"
 #include "polarssl/oid.h"
 
-static int pkcs5_parse_pbkdf2_params( unsigned char **p,
-                                      const unsigned char *end,
+static int pkcs5_parse_pbkdf2_params( asn1_buf *params,
                                       asn1_buf *salt, int *iterations,
                                       int *keylen, md_type_t *md_type )
 {
     int ret;
-    size_t len = 0;
     asn1_buf prf_alg_oid;
+    unsigned char **p = &params->p;
+    const unsigned char *end = params->p + params->len;
 
+    if( params->tag != ( ASN1_CONSTRUCTED | ASN1_SEQUENCE ) )
+        return( POLARSSL_ERR_PKCS5_INVALID_FORMAT +
+                POLARSSL_ERR_ASN1_UNEXPECTED_TAG );
     /*
      *  PBKDF2-params ::= SEQUENCE {
      *    salt              OCTET STRING,
@@ -60,14 +63,6 @@
      *  }
      *
      */
-    if( ( ret = asn1_get_tag( p, end, &len,
-            ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
-    {
-        return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + ret );
-    }
-
-    end = *p + len;
-
     if( ( ret = asn1_get_tag( p, end, &salt->len, ASN1_OCTET_STRING ) ) != 0 )
         return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + ret );
 
@@ -89,7 +84,7 @@
     if( *p == end )
         return( 0 );
 
-    if( ( ret = asn1_get_tag( p, end, &prf_alg_oid.len, ASN1_OID ) ) != 0 )
+    if( ( ret = asn1_get_alg_null( p, end, &prf_alg_oid ) ) != 0 )
         return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + ret );
 
     if( !OID_CMP( OID_HMAC_SHA1, &prf_alg_oid ) )
@@ -110,11 +105,12 @@
                  unsigned char *output )
 {
     int ret, iterations = 0, keylen = 0;
-    unsigned char *p, *end, *end2;
-    asn1_buf kdf_alg_oid, enc_scheme_oid, salt;
+    unsigned char *p, *end;
+    asn1_buf kdf_alg_oid, enc_scheme_oid, kdf_alg_params, enc_scheme_params;
+    asn1_buf salt;
     md_type_t md_type = POLARSSL_MD_SHA1;
     unsigned char key[32], iv[32];
-    size_t len = 0, olen = 0;
+    size_t olen = 0;
     const md_info_t *md_info;
     const cipher_info_t *cipher_info;
     md_context_t md_ctx;
@@ -130,32 +126,19 @@
      *    encryptionScheme AlgorithmIdentifier {{PBES2-Encs}}
      *  }
      */
-    if( ( ret = asn1_get_tag( &p, end, &len,
-            ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
-    {
+    if( pbe_params->tag != ( ASN1_CONSTRUCTED | ASN1_SEQUENCE ) )
+        return( POLARSSL_ERR_PKCS5_INVALID_FORMAT +
+                POLARSSL_ERR_ASN1_UNEXPECTED_TAG );
+
+    if( ( ret = asn1_get_alg( &p, end, &kdf_alg_oid, &kdf_alg_params ) ) != 0 )
         return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + ret );
-    }
-
-    if( ( ret = asn1_get_tag( &p, end, &len,
-            ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
-    {
-        return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + ret );
-    }
-
-    end2 = p + len;
-
-    if( ( ret = asn1_get_tag( &p, end2, &kdf_alg_oid.len, ASN1_OID ) ) != 0 )
-        return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + ret );
-
-    kdf_alg_oid.p = p;
-    p += kdf_alg_oid.len;
 
     // Only PBKDF2 supported at the moment
     //
     if( !OID_CMP( OID_PKCS5_PBKDF2, &kdf_alg_oid ) )
         return( POLARSSL_ERR_PKCS5_FEATURE_UNAVAILABLE );
 
-    if( ( ret = pkcs5_parse_pbkdf2_params( &p, end2,
+    if( ( ret = pkcs5_parse_pbkdf2_params( &kdf_alg_params,
                                            &salt, &iterations, &keylen,
                                            &md_type ) ) != 0 )
     {
@@ -166,19 +149,8 @@
     if( md_info == NULL )
         return( POLARSSL_ERR_PKCS5_FEATURE_UNAVAILABLE );
 
-    if( ( ret = asn1_get_tag( &p, end, &len,
-            ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
-    {
+    if( ( ret = asn1_get_alg( &p, end, &enc_scheme_oid, &enc_scheme_params ) ) != 0 )
         return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + ret );
-    }
-
-    end2 = p + len;
-
-    if( ( ret = asn1_get_tag( &p, end2, &enc_scheme_oid.len, ASN1_OID ) ) != 0 )
-        return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + ret );
-
-    enc_scheme_oid.p = p;
-    p += enc_scheme_oid.len;
 
     if ( oid_get_cipher_alg( &enc_scheme_oid, &cipher_alg ) != 0 )
         return( POLARSSL_ERR_PKCS5_FEATURE_UNAVAILABLE );
@@ -189,13 +161,13 @@
 
     keylen = cipher_info->key_length / 8;
 
-    if( ( ret = asn1_get_tag( &p, end2, &len, ASN1_OCTET_STRING ) ) != 0 )
-        return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + ret );
-
-    if( len != cipher_info->iv_size )
+    if( enc_scheme_params.tag != ASN1_OCTET_STRING ||
+        enc_scheme_params.len != cipher_info->iv_size )
+    {
         return( POLARSSL_ERR_PKCS5_INVALID_FORMAT );
+    }
 
-    memcpy( iv, p, len );
+    memcpy( iv, enc_scheme_params.p, enc_scheme_params.len );
 
     if( ( ret = md_init_ctx( &md_ctx, md_info ) ) != 0 )
         return( ret );
diff --git a/library/x509parse.c b/library/x509parse.c
index 0335db4..c49c48a 100644
--- a/library/x509parse.c
+++ b/library/x509parse.c
@@ -182,34 +182,10 @@
                          x509_buf *alg )
 {
     int ret;
-    size_t len;
 
-    if( ( ret = asn1_get_tag( p, end, &len,
-            ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
+    if( ( ret = asn1_get_alg_null( p, end, alg ) ) != 0 )
         return( POLARSSL_ERR_X509_CERT_INVALID_ALG + ret );
 
-    end = *p + len;
-    alg->tag = **p;
-
-    if( ( ret = asn1_get_tag( p, end, &alg->len, ASN1_OID ) ) != 0 )
-        return( POLARSSL_ERR_X509_CERT_INVALID_ALG + ret );
-
-    alg->p = *p;
-    *p += alg->len;
-
-    if( *p == end )
-        return( 0 );
-
-    /*
-     * assume the algorithm parameters must be NULL
-     */
-    if( ( ret = asn1_get_tag( p, end, &len, ASN1_NULL ) ) != 0 )
-        return( POLARSSL_ERR_X509_CERT_INVALID_ALG + ret );
-
-    if( *p != end )
-        return( POLARSSL_ERR_X509_CERT_INVALID_ALG +
-                POLARSSL_ERR_ASN1_LENGTH_MISMATCH );
-
     return( 0 );
 }
 
@@ -451,8 +427,8 @@
     unsigned char *end2;
     pk_type_t pk_alg = POLARSSL_PK_NONE;
 
-    if( ( ret = x509_get_alg( p, end, pk_alg_oid ) ) != 0 )
-        return( ret );
+    if( ( ret = asn1_get_alg_null( p, end, pk_alg_oid ) ) != 0 )
+        return( POLARSSL_ERR_X509_CERT_INVALID_PUBKEY + ret );
 
     /*
      * only RSA public keys handled at this time
@@ -2149,7 +2125,7 @@
     if( rsa->ver != 0 )
         return( POLARSSL_ERR_X509_KEY_INVALID_VERSION + ret );
 
-    if( ( ret = x509_get_alg( &p, end, &pk_alg_oid ) ) != 0 )
+    if( ( ret = asn1_get_alg_null( &p, end, &pk_alg_oid ) ) != 0 )
         return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT + ret );
 
     /*
@@ -2190,7 +2166,7 @@
 {
     int ret;
     size_t len;
-    unsigned char *p, *end, *end2;
+    unsigned char *p, *end;
     x509_buf pbe_alg_oid, pbe_params;
     unsigned char buf[2048];
 #if defined(POLARSSL_PKCS12_C)
@@ -2228,26 +2204,8 @@
 
     end = p + len;
 
-    if( ( ret = asn1_get_tag( &p, end, &len,
-            ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
-    {
+    if( ( ret = asn1_get_alg( &p, end, &pbe_alg_oid, &pbe_params ) ) != 0 )
         return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT + ret );
-    }
-
-    end2 = p + len;
-
-    if( ( ret = asn1_get_tag( &p, end, &pbe_alg_oid.len, ASN1_OID ) ) != 0 )
-        return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT + ret );
-
-    pbe_alg_oid.p = p;
-    p += pbe_alg_oid.len;
-
-    /*
-     * Store the algorithm parameters
-     */
-    pbe_params.p = p;
-    pbe_params.len = end2 - p;
-    p += pbe_params.len;
 
     if( ( ret = asn1_get_tag( &p, end, &len, ASN1_OCTET_STRING ) ) != 0 )
         return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT + ret );