Extend cert_write example program by multiple cmd line options

This commit adds the following command line options to programs/x509/cert_write:
- version (val 1, 2, 3): Set the certificate's version (v1, v2, v3)
- authority_identifier (val 0, 1): Enable or disable the addition of the
                                   authority identifier extension.
- subject_identifier (val 0, 1): Enable or disable the addition of the
                                 subject identifier extension.
- basic_constraints (val 0, 1): Enable or disable the addition of the
                                basic constraints extension.
- md (val MD5, SHA1, SHA256, SHA512): Set the hash function used
                                      when creating the CRT.
diff --git a/programs/x509/cert_write.c b/programs/x509/cert_write.c
index 66e5f1d..45fd059 100644
--- a/programs/x509/cert_write.c
+++ b/programs/x509/cert_write.c
@@ -51,6 +51,7 @@
 #include "mbedtls/x509_csr.h"
 #include "mbedtls/entropy.h"
 #include "mbedtls/ctr_drbg.h"
+#include "mbedtls/md.h"
 #include "mbedtls/error.h"
 
 #include <stdio.h>
@@ -83,6 +84,11 @@
 #define DFL_MAX_PATHLEN         -1
 #define DFL_KEY_USAGE           0
 #define DFL_NS_CERT_TYPE        0
+#define DFL_VERSION             3
+#define DFL_AUTH_IDENT          1
+#define DFL_SUBJ_IDENT          1
+#define DFL_CONSTRAINTS         1
+#define DFL_DIGEST              MBEDTLS_MD_SHA256
 
 #define USAGE \
     "\n usage: cert_write param=<>...\n"                \
@@ -109,6 +115,20 @@
     "    not_after=%%s        default: 20301231235959\n"\
     "    is_ca=%%d            default: 0 (disabled)\n"  \
     "    max_pathlen=%%d      default: -1 (none)\n"     \
+    "    md=%%s               default: SHA256\n"        \
+    "                        Supported values:\n"       \
+    "                        MD5, SHA1, SHA256, SHA512\n"\
+    "    version=%%d           default: 3\n"            \
+    "                        Possible values: 1, 2, 3\n"\
+    "    subject_identifier   default: 1\n"             \
+    "                        Possible values: 0, 1\n"   \
+    "                        (Considered for v3 only)\n"\
+    "    authority_identifier default: 1\n"             \
+    "                        Possible values: 0, 1\n"   \
+    "                        (Considered for v3 only)\n"\
+    "    basic_constraints    default: 1\n"             \
+    "                        Possible values: 0, 1\n"   \
+    "                        (Considered for v3 only)\n"\
     "    key_usage=%%s        default: (empty)\n"       \
     "                        Comma-separated-list of values:\n"     \
     "                          digital_signature\n"     \
@@ -118,6 +138,7 @@
     "                          key_agreement\n"         \
     "                          key_cert_sign\n"  \
     "                          crl_sign\n"              \
+    "                        (Considered for v3 only)\n"\
     "    ns_cert_type=%%s     default: (empty)\n"       \
     "                        Comma-separated-list of values:\n"     \
     "                          ssl_client\n"            \
@@ -149,6 +170,11 @@
     int selfsign;               /* selfsign the certificate             */
     int is_ca;                  /* is a CA certificate                  */
     int max_pathlen;            /* maximum CA path length               */
+    int authority_identifier;   /* add authority identifier id to CRT   */
+    int subject_identifier;     /* add subject identifier id to CRT     */
+    int basic_constraints;      /* add basic constraints ext to CRT     */
+    int version;                /* CRT version                          */
+    mbedtls_md_type_t md;       /* Hash used for signing                */
     unsigned char key_usage;    /* key usage flags                      */
     unsigned char ns_cert_type; /* NS cert type                         */
 } opt;
@@ -207,7 +233,6 @@
      * Set to sane values
      */
     mbedtls_x509write_crt_init( &crt );
-    mbedtls_x509write_crt_set_md_alg( &crt, MBEDTLS_MD_SHA256 );
     mbedtls_pk_init( &loaded_issuer_key );
     mbedtls_pk_init( &loaded_subject_key );
     mbedtls_mpi_init( &serial );
@@ -243,6 +268,11 @@
     opt.max_pathlen         = DFL_MAX_PATHLEN;
     opt.key_usage           = DFL_KEY_USAGE;
     opt.ns_cert_type        = DFL_NS_CERT_TYPE;
+    opt.version             = DFL_VERSION;
+    opt.md                  = DFL_DIGEST;
+    opt.subject_identifier   = DFL_SUBJ_IDENT;
+    opt.authority_identifier = DFL_AUTH_IDENT;
+    opt.basic_constraints    = DFL_CONSTRAINTS;
 
     for( i = 1; i < argc; i++ )
     {
@@ -286,6 +316,52 @@
         {
             opt.serial = q;
         }
+        else if( strcmp( p, "authority_identifier" ) == 0 )
+        {
+            opt.authority_identifier = atoi( q );
+            if( opt.authority_identifier != 0 &&
+                opt.authority_identifier != 1 )
+            {
+                goto usage;
+            }
+        }
+        else if( strcmp( p, "subject_identifier" ) == 0 )
+        {
+            opt.subject_identifier = atoi( q );
+            if( opt.subject_identifier != 0 &&
+                opt.subject_identifier != 1 )
+            {
+                goto usage;
+            }
+        }
+        else if( strcmp( p, "basic_constraints" ) == 0 )
+        {
+            opt.basic_constraints = atoi( q );
+            if( opt.basic_constraints != 0 &&
+                opt.basic_constraints != 1 )
+            {
+                goto usage;
+            }
+        }
+        else if( strcmp( p, "md" ) == 0 )
+        {
+            if( strcmp( q, "SHA1" ) == 0 )
+                opt.md = MBEDTLS_MD_SHA1;
+            else if( strcmp( q, "SHA256" ) == 0 )
+                opt.md = MBEDTLS_MD_SHA256;
+            else if( strcmp( q, "SHA512" ) == 0 )
+                opt.md = MBEDTLS_MD_SHA512;
+            else if( strcmp( q, "MD5" ) == 0 )
+                opt.md = MBEDTLS_MD_MD5;
+            else
+                goto usage;
+        }
+        else if( strcmp( p, "version" ) == 0 )
+        {
+            opt.version = atoi( q );
+            if( opt.version < 1 || opt.version > 3 )
+                goto usage;
+        }
         else if( strcmp( p, "selfsign" ) == 0 )
         {
             opt.selfsign = atoi( q );
@@ -540,6 +616,9 @@
     mbedtls_printf( "  . Setting certificate values ..." );
     fflush( stdout );
 
+    mbedtls_x509write_crt_set_version( &crt, opt.version - 1 );
+    mbedtls_x509write_crt_set_md_alg( &crt, opt.md );
+
     ret = mbedtls_x509write_crt_set_serial( &crt, &serial );
     if( ret != 0 )
     {
@@ -558,49 +637,63 @@
 
     mbedtls_printf( " ok\n" );
 
-    mbedtls_printf( "  . Adding the Basic Constraints extension ..." );
-    fflush( stdout );
-
-    ret = mbedtls_x509write_crt_set_basic_constraints( &crt, opt.is_ca,
-                                               opt.max_pathlen );
-    if( ret != 0 )
+    if( opt.version == 3 && opt.basic_constraints )
     {
-        mbedtls_strerror( ret, buf, 1024 );
-        mbedtls_printf( " failed\n  !  x509write_crt_set_basic_contraints returned -0x%02x - %s\n\n", -ret, buf );
-        goto exit;
-    }
+        mbedtls_printf( "  . Adding the Basic Constraints extension ..." );
+        fflush( stdout );
 
-    mbedtls_printf( " ok\n" );
+        ret = mbedtls_x509write_crt_set_basic_constraints( &crt, opt.is_ca,
+                                                           opt.max_pathlen );
+        if( ret != 0 )
+        {
+            mbedtls_strerror( ret, buf, 1024 );
+            mbedtls_printf( " failed\n  !  x509write_crt_set_basic_contraints "
+                            "returned -0x%02x - %s\n\n", -ret, buf );
+            goto exit;
+        }
+
+        mbedtls_printf( " ok\n" );
+    }
 
 #if defined(MBEDTLS_SHA1_C)
-    mbedtls_printf( "  . Adding the Subject Key Identifier ..." );
-    fflush( stdout );
-
-    ret = mbedtls_x509write_crt_set_subject_key_identifier( &crt );
-    if( ret != 0 )
+    if( opt.version == 3 && opt.subject_identifier )
     {
-        mbedtls_strerror( ret, buf, 1024 );
-        mbedtls_printf( " failed\n  !  mbedtls_x509write_crt_set_subject_key_identifier returned -0x%02x - %s\n\n", -ret, buf );
-        goto exit;
+        mbedtls_printf( "  . Adding the Subject Key Identifier ..." );
+        fflush( stdout );
+
+        ret = mbedtls_x509write_crt_set_subject_key_identifier( &crt );
+        if( ret != 0 )
+        {
+            mbedtls_strerror( ret, buf, 1024 );
+            mbedtls_printf( " failed\n  !  mbedtls_x509write_crt_set_subject"
+                            "_key_identifier returned -0x%02x - %s\n\n",
+                            -ret, buf );
+            goto exit;
+        }
+
+        mbedtls_printf( " ok\n" );
     }
 
-    mbedtls_printf( " ok\n" );
-
-    mbedtls_printf( "  . Adding the Authority Key Identifier ..." );
-    fflush( stdout );
-
-    ret = mbedtls_x509write_crt_set_authority_key_identifier( &crt );
-    if( ret != 0 )
+    if( opt.version == 3 && opt.authority_identifier )
     {
-        mbedtls_strerror( ret, buf, 1024 );
-        mbedtls_printf( " failed\n  !  mbedtls_x509write_crt_set_authority_key_identifier returned -0x%02x - %s\n\n", -ret, buf );
-        goto exit;
-    }
+        mbedtls_printf( "  . Adding the Authority Key Identifier ..." );
+        fflush( stdout );
 
-    mbedtls_printf( " ok\n" );
+        ret = mbedtls_x509write_crt_set_authority_key_identifier( &crt );
+        if( ret != 0 )
+        {
+            mbedtls_strerror( ret, buf, 1024 );
+            mbedtls_printf( " failed\n  !  mbedtls_x509write_crt_set_authority_"
+                            "key_identifier returned -0x%02x - %s\n\n",
+                            -ret, buf );
+            goto exit;
+        }
+
+        mbedtls_printf( " ok\n" );
+    }
 #endif /* MBEDTLS_SHA1_C */
 
-    if( opt.key_usage )
+    if( opt.version == 3 && opt.key_usage )
     {
         mbedtls_printf( "  . Adding the Key Usage extension ..." );
         fflush( stdout );
@@ -616,7 +709,7 @@
         mbedtls_printf( " ok\n" );
     }
 
-    if( opt.ns_cert_type )
+    if( opt.version == 3 && opt.ns_cert_type )
     {
         mbedtls_printf( "  . Adding the NS Cert Type extension ..." );
         fflush( stdout );