--- include/polarssl/x509.h
+++ include/polarssl/x509.h
@@ -73,6 +73,8 @@
#define POLARSSL_ERR_X509_FILE_IO_ERROR -0x2B00 /**< Read/write of file failed. */
#define POLARSSL_ERR_X509_PASSWORD_REQUIRED -0x2B80 /**< Private key password can't be empty. */
#define POLARSSL_ERR_X509_PASSWORD_MISMATCH -0x2C00 /**< Given private key password does not allow for correct decryption. */
+#define POLARSSL_ERR_X509_POINT_ERROR -0x2C80
+#define POLARSSL_ERR_X509_VALUE_TO_LENGTH -0x2D00
/* \} name */
@@ -394,11 +396,9 @@
/**
* \name Structures for writing X.509 certificates.
- * XvP: commented out as they are not used.
* - typedef struct _x509_node x509_node;
* - typedef struct _x509_raw x509_raw;
*/
-/*
typedef struct _x509_node
{
unsigned char *data;
@@ -426,7 +426,6 @@
x509_node sign;
}
x509_raw;
-*/
#ifdef __cplusplus
extern "C" {
@@ -794,6 +793,229 @@
*/
int x509_self_test( int verbose );
+/**
+ * \brief Write a certificate info file
+ *
+ * \param chain points to the raw certificate data
+ * \param path filename to write the certificate to
+ * \param format X509_OUTPUT_DER or X509_OUTPUT_PEM
+ *
+ * \return 0 if successful, or a specific X509 error code
+ */
+int x509write_crtfile( x509_raw *chain,
+ unsigned char *path,
+ int format );
+
+/**
+ * \brief Write a certificate signing request message format file
+ *
+ * \param chain points to the raw certificate (with x509write_create_csr) data
+ * \param path filename to write the certificate to
+ * \param format X509_OUTPUT_DER or X509_OUTPUT_PEM
+ *
+ * \return 0 if successful, or a specific X509 error code
+ */
+int x509write_csrfile( x509_raw *chain,
+ unsigned char *path,
+ int format );
+
+/*
+ * \brief Write a private RSA key into a file
+ *
+ * \param rsa points to an RSA key
+ * \param path filename to write the key to
+ * \param format X509_OUTPUT_DER or X509_OUTPUT_PEM
+ *
+ * \return 0 if successful, or a specific X509 error code
+ */
+int x509write_keyfile( rsa_context *rsa,
+ char *path,
+ int format );
+
+/**
+ * \brief Add a public key to certificate
+ *
+ * \param chain points to the raw certificate data
+ * \param pubkey points to an RSA key
+ *
+ * \return 0 if successful, or a specific X509 error code
+ */
+int x509write_add_pubkey( x509_raw *chain, rsa_context *pubkey );
+
+/**
+ * \brief Create x509 subject/issuer field to raw certificate
+ * from string or CA cert. Make string NULL if you will
+ * use the CA copy function or make CA NULL then used
+ * the string parse.
+ *
+ * \param chain points to the raw certificate data
+ * \param names a string that can hold (separete with ";"):
+ * CN=CommonName
+ * -- O=Organization
+ * -- OU=OrgUnit
+ * -- ST=State
+ * -- L=Locality
+ * -- R=Email
+ * -- C=Country
+ * . Make that NULL if you didn't need that.
+ * \param flag flag is X509_ISSUER or X509_SUBJECT that defined
+ * where change
+ * \param ca the certificate for copy data. Make that NULL if you
+ * didn't need that.
+ * \param ca_flag set the ca field from copy to crt
+ *
+ * \return 0 if successful, or a specific X509 error code
+ */
+int x509write_add_customize ( x509_raw *crt,
+ unsigned char *names,
+ int flag,
+ x509_cert *ca,
+ int ca_flag );
+
+/**
+* \brief Add x509 issuer field
+*
+* \param chain points to the raw certificate data
+* \param issuer a string holding (separete with ";"):
+* CN=CommonName
+* -- O=Organization
+* -- OU=OrgUnit
+* -- ST=State
+* -- L=Locality
+* -- R=Email
+* -- C=Country
+* . Set this to NULL if not needed.
+* \return 0 if successful, or a specific X509 error code
+*/
+int x509write_add_issuer( x509_raw *crt, unsigned char *issuer);
+
+/**
+ * \brief Add x509 subject field
+ *
+ * \param chain points to the raw certificate data
+ * \param subject a string holding (separete with ";"):
+ * CN=CommonName
+ * -- O=Organization
+ * -- OU=OrgUnit
+ * -- ST=State
+ * -- L=Locality
+ * -- R=Email
+ * -- C=Country
+ * . Set this to NULL if not needed.
+ * \return 0 if successful, or a specific X509 error code
+ */
+int x509write_add_subject( x509_raw *crt, unsigned char *subject);
+
+/**
+* \brief Copy x509 issuer field from another certificate
+*
+* \param chain points to the raw certificate data
+* \param from_crt the certificate whose issuer is to be copied.
+* \return 0 if successful, or a specific X509 error code
+*/
+int x509write_copy_issuer(x509_raw *crt, x509_cert *from_crt);
+
+/**
+* \brief Copy x509 subject field from another certificate
+*
+* \param chain points to the raw certificate data
+* \param from_crt the certificate whose subject is to be copied.
+* \return 0 if successful, or a specific X509 error code
+*/
+int x509write_copy_subject(x509_raw *crt, x509_cert *from_crt);
+
+/**
+* \brief Copy x509 issuer field from the subject of another certificate
+*
+* \param chain points to the raw certificate data
+* \param from_crt the certificate whose subject is to be copied.
+* \return 0 if successful, or a specific X509 error code
+*/
+int x509write_copy_issuer_from_subject(x509_raw *crt, x509_cert *from_crt);
+
+/**
+* \brief Copy x509 subject field from the issuer of another certificate
+*
+* \param chain points to the raw certificate data
+* \param from_crt the certificate whose issuer is to be copied.
+* \return 0 if successful, or a specific X509 error code
+*/
+int x509write_copy_subject_from_issuer(x509_raw *crt, x509_cert *from_crt);
+
+/**
+ * \brief Create x509 validity time in UTC
+ *
+ * \param chain points to the raw certificate data
+ * \param before valid not before in format YYYY-MM-DD hh:mm:ss
+ * \param after valid not after in format YYYY-MM-DD hh:mm:ss
+ *
+ * \return 0 if successful, or a specific X509 error code
+ */
+int x509write_add_validity( x509_raw *crt,
+ unsigned char *before,
+ unsigned char *after );
+
+/**
+ * \brief Create a self-signed certificate
+ *
+ * \param chain points to the raw certificate data
+ * \param rsa a private key to sign the certificate
+ *
+ * \return 0 if successful, or a specific X509 error code
+ */
+int x509write_create_selfsign( x509_raw *crt, rsa_context *raw );
+
+/**
+ * \brief Create a certificate
+ *
+ * \param chain points to the raw certificate data
+ * \param rsa a private key to sign the certificate
+ *
+ * \return 0 if successful, or a specific X509 error code
+ */
+int x509write_create_sign( x509_raw *crt, rsa_context *raw );
+
+/**
+ * \brief Create a certificate signing request
+ *
+ * \param chain points to the raw certificate data. Didn't use the
+ * same chain that u have use for certificate.
+ * \param privkey a rsa private key
+ *
+ * \return 0 if successful, or a specific X509 error code
+ */
+int x509write_create_csr( x509_raw *chain, rsa_context *privkey );
+
+/**
+ * \brief Serialize an rsa key into DER
+ *
+ * \param rsa a rsa key for output
+ * \param node a x509 node for write into
+ *
+ * \return 0 if successful, or a specific X509 error code
+ */
+int x509write_serialize_key( rsa_context *rsa, x509_node *node );
+
+/**
+ * \brief Unallocate all raw certificate data
+ */
+void x509write_free_raw( x509_raw *crt );
+
+/**
+ * \brief Allocate all raw certificate data
+ */
+void x509write_init_raw( x509_raw *crt );
+
+/**
+ * \brief Unallocate all node certificate data
+ */
+void x509write_free_node( x509_node *crt_node );
+
+/**
+ * \brief Allocate all node certificate data
+ */
+void x509write_init_node( x509_node *crt_node );
+
#ifdef __cplusplus
}
#endif
--- library/x509write.c
+++ library/x509write.c
@@ -1,4 +1,1139 @@
/*
+ * X.509 certificate and private key writing
+ *
+ * Copyright (C) 2006-2007 Pascal Vizeli
+ * Modifications (C) 2009 Steven Barth
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License, version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+/*
+ * The ITU-T X.509 standard defines a certificat format for PKI.
+ *
+ * http://www.ietf.org/rfc/rfc2459.txt
+ * http://www.ietf.org/rfc/rfc3279.txt
+ *
+ * ftp://ftp.rsasecurity.com/pub/pkcs/ascii/pkcs-1v2.asc
+ *
+ * http://www.itu.int/ITU-T/studygroups/com17/languages/X.680-0207.pdf
+ * http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf
+ *
+ * For CRS:
+ * http://www.faqs.org/rfcs/rfc2314.html
+ */
+#include "polarssl/config.h"
+#include "polarssl/x509.h"
+#include "polarssl/base64.h"
+#include "polarssl/sha1.h"
+
+#include
+#include
+#include
+#include
+#include
+
+#define and &&
+#define or ||
+
+#if defined _MSC_VER && !defined snprintf
+#define snprintf _snprintf
+#endif
+
+static int x509write_realloc_node(x509_node *node, size_t larger);
+static int x509write_file(x509_node *node, char *path, int format, const char* pem_prolog, const char* pem_epilog);
+
+/*
+ * evaluate how mani octet have this integer
+ */
+static int asn1_eval_octet(unsigned int digit)
+{
+ int i, byte;
+
+ for (byte = 4, i = 24; i >= 0; i -= 8, --byte)
+ if (((digit >> i) & 0xFF) != 0)
+ return byte;
+
+ return 0;
+}
+
+/*
+ * write the asn.1 lenght form into p
+ */
+static int asn1_add_len(unsigned int size, x509_node *node)
+{
+ if (size > 127) {
+
+ /* long size */
+ int byte = asn1_eval_octet(size);
+ int i = 0;
+
+ *(node->p) = (0x80 | byte) & 0xFF;
+ ++node->p;
+
+ for (i = byte; i > 0; --i) {
+
+ *(node->p) = (size >> ((i - 1) * 8)) & 0xFF;
+ ++node->p;
+ }
+
+ } else {
+
+ /* short size */
+ *(node->p) = size & 0xFF;
+ if (size != 0)
+ ++node->p;
+ }
+
+ return 0;
+}
+
+/*
+ * write a ans.1 object into p
+ */
+static int asn1_add_obj(unsigned char *value, unsigned int size, int tag,
+ x509_node *node)
+{
+ int tl = 2;
+
+ if (tag == ASN1_BIT_STRING)
+ ++tl;
+
+ if (size > 127)
+ x509write_realloc_node(node, (size_t) size + tl +
+ asn1_eval_octet(size));
+ else
+ x509write_realloc_node(node, (size_t) size + tl);
+
+ if (node->data == NULL)
+ return 1;
+
+ /* tag */
+ *(node->p) = tag & 0xFF;
+ ++node->p;
+
+ /* len */
+ if (tag == ASN1_BIT_STRING) {
+ asn1_add_len((unsigned int) size + 1, node);
+ *(node->p) = 0x00;
+ ++node->p;
+ } else {
+ asn1_add_len((unsigned int) size, node);
+ }
+
+ /* value */
+ if (size > 0) {
+
+ memcpy(node->p, value, (size_t) size);
+ if ((node->p += size -1) != node->end)
+ return POLARSSL_ERR_X509_POINT_ERROR;
+ } else {
+ /* make nothing -> NULL */
+ }
+
+ return 0;
+}
+
+/*
+ * write a asn.1 conform integer object
+ */
+static int asn1_add_int(signed int value, x509_node *node)
+{
+ signed int i = 0, neg = 1;
+ unsigned int byte, u_val = 0, tmp_val = 0;
+
+ /* if negate? */
+ if (value < 0) {
+ neg = -1;
+ u_val = ~value;
+ } else {
+ u_val = value;
+ }
+
+ byte = asn1_eval_octet(u_val);
+ /* 0 isn't NULL */
+ if (byte == 0)
+ byte = 1;
+
+ /* ASN.1 integer is signed! */
+ if (byte < 4 and ((u_val >> ((byte -1) * 8)) & 0xFF) == 0x80)
+ byte += 1;
+
+ if (x509write_realloc_node(node, (size_t) byte + 2) != 0)
+ return 1;
+
+ /* tag */
+ *(node->p) = ASN1_INTEGER;
+ ++node->p;
+
+ /* len */
+ asn1_add_len(byte, node);
+
+ /* value */
+ for (i = byte; i > 0; --i) {
+
+ tmp_val = (u_val >> ((i - 1) * 8)) & 0xFF;
+ if (neg == 1)
+ *(node->p) = tmp_val;
+ else
+ *(node->p) = ~tmp_val;
+
+ if (i > 1)
+ ++node->p;
+ }
+
+ if (node->p != node->end)
+ return POLARSSL_ERR_X509_POINT_ERROR;
+
+ return 0;
+}
+
+/*
+ * write a asn.1 conform mpi object
+ */
+static int asn1_add_mpi(mpi *value, int tag, x509_node *node)
+{
+ size_t size = (mpi_msb(value) / 8) + 1;
+ unsigned char *buf;
+ int buf_len = (int) size, tl = 2;
+
+ if (tag == ASN1_BIT_STRING)
+ ++tl;
+
+ if (size > 127)
+ x509write_realloc_node(node, size + (size_t) tl +
+ asn1_eval_octet((unsigned int)size));
+ else
+ x509write_realloc_node(node, size + (size_t) tl);
+
+ if (node->data == NULL)
+ return 1;
+
+ buf = (unsigned char*) malloc(size);
+ if (mpi_write_binary(value, buf, buf_len) != 0)
+ return POLARSSL_ERR_MPI_BUFFER_TOO_SMALL;
+
+ /* tag */
+ *(node->p) = tag & 0xFF;
+ ++node->p;
+
+ /* len */
+ if (tag == ASN1_BIT_STRING) {
+ asn1_add_len((unsigned int) size + 1, node);
+ *(node->p) = 0x00;
+ ++node->p;
+ } else {
+ asn1_add_len((unsigned int) size, node);
+ }
+
+ /* value */
+ memcpy(node->p, buf, size);
+ free(buf);
+
+ if ((node->p += (int) size -1) != node->end)
+ return POLARSSL_ERR_X509_POINT_ERROR;
+
+ return 0;
+}
+
+/*
+ * write a node into asn.1 conform object
+ */
+static int asn1_append_tag(x509_node *node, int tag)
+{
+ int tl = 2;
+
+ x509_node tmp;
+ x509write_init_node(&tmp);
+
+ if (tag == ASN1_BIT_STRING)
+ ++tl;
+
+ if (node->len > 127)
+ x509write_realloc_node(&tmp, node->len + (size_t) tl +
+ asn1_eval_octet((unsigned int)node->len));
+ else
+ x509write_realloc_node(&tmp, node->len + (size_t) tl);
+
+ if (tmp.data == NULL) {
+ x509write_free_node(&tmp);
+ return 1;
+ }
+
+ /* tag */
+ *(tmp.p) = tag & 0xFF;
+ ++tmp.p;
+
+ /* len */
+ if (tag == ASN1_BIT_STRING) {
+ asn1_add_len((unsigned int) node->len + 1, &tmp);
+ *(tmp.p) = 0x00;
+ ++tmp.p;
+ } else {
+ asn1_add_len((unsigned int) node->len, &tmp);
+ }
+
+ /* value */
+ memcpy(tmp.p, node->data, node->len);
+
+ /* good? */
+ if ((tmp.p += (int) node->len -1) != tmp.end) {
+ x509write_free_node(&tmp);
+ return POLARSSL_ERR_X509_POINT_ERROR;
+ }
+
+ free(node->data);
+ node->data = tmp.data;
+ node->p = tmp.p;
+ node->end = tmp.end;
+ node->len = tmp.len;
+
+ return 0;
+}
+
+/*
+ * write nodes into a asn.1 object
+ */
+static int asn1_append_nodes(x509_node *node, int tag, int anz, ...)
+{
+ va_list ap;
+ size_t size = 0;
+ x509_node *tmp;
+ int count;
+
+ va_start(ap, anz);
+ count = anz;
+
+ while (count--) {
+
+ tmp = va_arg(ap, x509_node*);
+ if (tmp->data != NULL)
+ size += tmp->len;
+ }
+
+ if ( size > 127) {
+ if (x509write_realloc_node(node, size + (size_t) 2 +
+ asn1_eval_octet(size)) != 0)
+ return 1;
+ } else {
+ if (x509write_realloc_node(node, size + (size_t) 2) != 0)
+ return 1;
+ }
+
+ /* tag */
+ *(node->p) = tag & 0xFF;
+ ++node->p;
+
+ /* len */
+ asn1_add_len(size, node);
+
+ /* value */
+ va_start(ap, anz);
+ count = anz;
+
+ while (count--) {
+
+ tmp = va_arg(ap, x509_node*);
+ if (tmp->data != NULL) {
+
+ memcpy(node->p, tmp->data, tmp->len);
+ if ((node->p += (int) tmp->len -1) != node->end)
+ ++node->p;
+ }
+ }
+
+ va_end(ap);
+ return 0;
+}
+
+/*
+ * write a ASN.1 conform object identifiere include a "tag"
+ */
+static int asn1_add_oid(x509_node *node, unsigned char *oid, size_t len,
+ int tag, int tag_val, unsigned char *value, size_t val_len)
+{
+ int ret;
+ x509_node tmp;
+
+ x509write_init_node(&tmp);
+
+ /* OBJECT IDENTIFIER */
+ if ((ret = asn1_add_obj(oid, len, ASN1_OID, &tmp)) != 0) {
+ x509write_free_node(&tmp);
+ return ret;
+ }
+
+ /* value */
+ if ((ret = asn1_add_obj(value, val_len, tag_val, &tmp)) != 0) {
+ x509write_free_node(&tmp);
+ return ret;
+ }
+
+ /* SET/SEQUENCE */
+ if ((ret = asn1_append_nodes(node, tag, 1, &tmp)) != 0) {
+ x509write_free_node(&tmp);
+ return ret;
+ }
+
+ x509write_free_node(&tmp);
+ return 0;
+}
+
+/*
+ * utcTime UTCTime
+ */
+static int asn1_add_date_utc(unsigned char *time, x509_node *node)
+{
+ unsigned char date[13], *sp;
+ x509_time xtime;
+ int ret;
+
+ sscanf((char*)time, "%d-%d-%d %d:%d:%d", &xtime.year, &xtime.mon,
+ &xtime.day, &xtime.hour, &xtime.min, &xtime.sec);
+
+ /* convert to YY */
+ if (xtime.year > 2000)
+ xtime.year -= 2000;
+ else
+ xtime.year -= 1900;
+
+ snprintf((char*)date, 13, "%2d%2d%2d%2d%2d%2d", xtime.year, xtime.mon, xtime.day,
+ xtime.hour, xtime.min, xtime.sec);
+
+ /* replace ' ' to '0' */
+ for (sp = date; *sp != '\0'; ++sp)
+ if (*sp == '\x20')
+ *sp = '\x30';
+
+ date[12] = 'Z';
+
+ if ((ret = asn1_add_obj(date, 13, ASN1_UTC_TIME, node)) != 0)
+ return ret;
+
+ return 0;
+}
+
+/*
+ * serialize an rsa key into DER
+ */
+
+int x509write_serialize_key(rsa_context *rsa, x509_node *node)
+{
+ int ret = 0;
+ x509write_init_node(node);
+
+ /* vers, n, e, d, p, q, dp, dq, pq */
+ if ((ret = asn1_add_int(rsa->ver, node)) != 0)
+ return ret;
+ if ((ret = asn1_add_mpi(&rsa->N, ASN1_INTEGER, node)) != 0)
+ return ret;
+ if ((ret = asn1_add_mpi(&rsa->E, ASN1_INTEGER, node)) != 0)
+ return ret;
+ if ((ret = asn1_add_mpi(&rsa->D, ASN1_INTEGER, node)) != 0)
+ return ret;
+ if ((ret = asn1_add_mpi(&rsa->P, ASN1_INTEGER, node)) != 0)
+ return ret;
+ if ((ret = asn1_add_mpi(&rsa->Q, ASN1_INTEGER, node)) != 0)
+ return ret;
+ if ((ret = asn1_add_mpi(&rsa->DP, ASN1_INTEGER, node)) != 0)
+ return ret;
+ if ((ret = asn1_add_mpi(&rsa->DQ, ASN1_INTEGER, node)) != 0)
+ return ret;
+ if ((ret = asn1_add_mpi(&rsa->QP, ASN1_INTEGER, node)) != 0)
+ return ret;
+ if ((ret = asn1_append_tag(node, ASN1_CONSTRUCTED | ASN1_SEQUENCE)) != 0)
+ return ret;
+
+ return 0;
+}
+
+/*
+ * write a der/pem encoded rsa private key into a file
+ */
+int x509write_keyfile(rsa_context *rsa, char *path, int out_flag)
+{
+ int ret = 0;
+ const char key_beg[] = "-----BEGIN RSA PRIVATE KEY-----\n",
+ key_end[] = "-----END RSA PRIVATE KEY-----\n";
+ x509_node node;
+
+ x509write_init_node(&node);
+ if ((ret = x509write_serialize_key(rsa,&node)) != 0) {
+ x509write_free_node(&node);
+ return ret;
+ }
+
+ ret = x509write_file(&node,path,out_flag,key_beg,key_end);
+ x509write_free_node(&node);
+
+ return ret;
+}
+
+
+/*
+ * reasize the memory for node
+ */
+static int x509write_realloc_node(x509_node *node, size_t larger)
+{
+ /* init len */
+ if (node->data == NULL) {
+ node->len = 0;
+ node->data = malloc(larger);
+ if(node->data == NULL)
+ return 1;
+ } else {
+ /* realloc memory */
+ if ((node->data = realloc(node->data, node->len + larger)) == NULL)
+ return 1;
+ }
+
+ /* init pointer */
+ node->p = &node->data[node->len];
+ node->len += larger;
+ node->end = &node->data[node->len -1];
+
+ return 0;
+}
+
+/*
+ * init node
+ */
+void x509write_init_node(x509_node *node)
+{
+ memset(node, 0, sizeof(x509_node));
+}
+
+/*
+ * clean memory
+ */
+void x509write_free_node(x509_node *node)
+{
+ if (node->data != NULL)
+ free(node->data);
+ node->p = NULL;
+ node->end = NULL;
+ node->len = 0;
+}
+
+/*
+ * write a x509 certificate into file
+ */
+int x509write_crtfile(x509_raw *chain, unsigned char *path, int out_flag)
+{
+ const char cer_beg[] = "-----BEGIN CERTIFICATE-----\n",
+ cer_end[] = "-----END CERTIFICATE-----\n";
+
+ return x509write_file(&chain->raw, (char*)path, out_flag, cer_beg, cer_end);
+}
+
+/*
+ * write a x509 certificate into file
+ */
+int x509write_csrfile(x509_raw *chain, unsigned char *path, int out_flag)
+{
+ const char cer_beg[] = "-----BEGIN CERTIFICATE REQUEST-----\n",
+ cer_end[] = "-----END CERTIFICATE REQUEST-----\n";
+
+ return x509write_file(&chain->raw, (char*)path, out_flag, cer_beg, cer_end);
+}
+
+/*
+ * write an x509 file
+ */
+static int x509write_file(x509_node *node, char *path, int format,
+ const char* pem_prolog, const char* pem_epilog)
+{
+ FILE *ofstream;
+ int is_err = 1, buf_len, i, n;
+ char* base_buf;
+
+ if ((ofstream = fopen(path, "wb")) == NULL)
+ return 1;
+
+ switch (format) {
+ case X509_OUTPUT_DER:
+ if (fwrite(node->data, 1, node->len, ofstream)
+ != node->len)
+ is_err = -1;
+ break;
+ case X509_OUTPUT_PEM:
+ if (fprintf(ofstream,pem_prolog)<0) {
+ is_err = -1;
+ break;
+ }
+
+ buf_len = node->len << 1;
+ base_buf = (char*) malloc((size_t)buf_len);
+ memset(base_buf,0,buf_len);
+ if (base64_encode(base_buf, &buf_len, node->data,
+ (int) node->len) != 0) {
+ is_err = -1;
+ break;
+ }
+
+ n=strlen(base_buf);
+ for(i=0;isubpubkey;
+
+ x509write_init_node(&n_tmp);
+ x509write_init_node(&n_tmp2);
+
+ /*
+ * RSAPublicKey ::= SEQUENCE {
+ * modulus INTEGER, -- n
+ * publicExponent INTEGER -- e
+ * }
+ */
+ if ((ret = asn1_add_mpi(&pubkey->N, ASN1_INTEGER, &n_tmp)) != 0) {
+ x509write_free_node(&n_tmp);
+ x509write_free_node(&n_tmp2);
+ return ret;
+ }
+ if ((ret = asn1_add_mpi(&pubkey->E, ASN1_INTEGER, &n_tmp)) != 0) {
+ x509write_free_node(&n_tmp);
+ x509write_free_node(&n_tmp2);
+ return ret;
+ }
+ if ((ret = asn1_append_tag(&n_tmp, ASN1_CONSTRUCTED | ASN1_SEQUENCE))
+ != 0) {
+ x509write_free_node(&n_tmp);
+ x509write_free_node(&n_tmp2);
+ return ret;
+ }
+
+ /*
+ * SubjectPublicKeyInfo ::= SEQUENCE {
+ * algorithm AlgorithmIdentifier,
+ * subjectPublicKey BIT STRING }
+ */
+ if ((ret = asn1_append_tag(&n_tmp, ASN1_BIT_STRING)) != 0) {
+ x509write_free_node(&n_tmp);
+ x509write_free_node(&n_tmp2);
+ return ret;
+ }
+ if ((ret = asn1_add_oid(&n_tmp2, (unsigned char*)OID_PKCS1_RSA, 9,
+ ASN1_CONSTRUCTED | ASN1_SEQUENCE, ASN1_NULL,
+ (unsigned char *)"", 0)) != 0) {
+ x509write_free_node(&n_tmp);
+ x509write_free_node(&n_tmp2);
+ return ret;
+ }
+
+ if ((ret = asn1_append_nodes(node, ASN1_CONSTRUCTED | ASN1_SEQUENCE, 2,
+ &n_tmp2, &n_tmp))) {
+ x509write_free_node(&n_tmp);
+ x509write_free_node(&n_tmp2);
+ return ret;
+ }
+
+ x509write_free_node(&n_tmp);
+ x509write_free_node(&n_tmp2);
+ return 0;
+}
+
+/*
+ * RelativeDistinguishedName ::=
+ * SET OF AttributeTypeAndValue
+ *
+ * AttributeTypeAndValue ::= SEQUENCE {
+ * type AttributeType,
+ * value AttributeValue }
+ */
+static int x509write_add_name(x509_node *node, unsigned char *oid,
+ unsigned int oid_len, unsigned char *value, int len, int value_tag)
+{
+ int ret;
+ x509_node n_tmp;
+
+ x509write_init_node(&n_tmp);
+
+ if ((ret = asn1_add_oid(&n_tmp, oid, oid_len,
+ ASN1_CONSTRUCTED | ASN1_SEQUENCE, value_tag,
+ value, len))) {
+ x509write_free_node(&n_tmp);
+ return ret;
+ }
+
+ if ((asn1_append_nodes(node, ASN1_CONSTRUCTED | ASN1_SET, 1, &n_tmp))
+ != 0) {
+ x509write_free_node(&n_tmp);
+ return ret;
+ }
+
+ x509write_free_node(&n_tmp);
+ return 0;
+}
+
+/*
+ * Parse the name string and add to node
+ */
+static int x509write_parse_names(x509_node *node, unsigned char *names)
+{
+ unsigned char *sp, *begin = NULL;
+ unsigned char oid[3] = OID_X520, tag[4], *tag_sp = tag;
+ unsigned char *C = NULL, *CN = NULL, *O = NULL, *OU = NULL,
+ *ST = NULL, *L = NULL, *R = NULL;
+ int C_len = 0, CN_len = 0, O_len = 0, OU_len = 0, ST_len = 0,
+ L_len = 0, R_len = 0;
+ int ret = 0, is_tag = 1, is_begin = -1, len = 0;
+
+
+ for (sp = names; ; ++sp) {
+
+ /* filter tag */
+ if (is_tag == 1) {
+
+ if (tag_sp == &tag[3])
+ return POLARSSL_ERR_X509_VALUE_TO_LENGTH;
+
+ /* is tag end? */
+ if (*sp == '=') {
+ is_tag = -1;
+ *tag_sp = '\0';
+ is_begin = 1;
+ /* set len 0 (reset) */
+ len = 0;
+ } else {
+ /* tag hasn't ' '! */
+ if (*sp != ' ') {
+ *tag_sp = *sp;
+ ++tag_sp;
+ }
+ }
+ /* filter value */
+ } else {
+
+ /* set pointer of value begin */
+ if (is_begin == 1) {
+ begin = sp;
+ is_begin = -1;
+ }
+
+ /* is value at end? */
+ if (*sp == ';' or *sp == '\0') {
+ is_tag = 1;
+
+ /* common name */
+ if (tag[0] == 'C' and tag[1] == 'N') {
+ CN = begin;
+ CN_len = len;
+
+ /* organization */
+ } else if (tag[0] == 'O' and tag[1] == '\0') {
+ O = begin;
+ O_len = len;
+
+ /* country */
+ } else if (tag[0] == 'C' and tag[1] == '\0') {
+ C = begin;
+ C_len = len;
+
+ /* organisation unit */
+ } else if (tag[0] == 'O' and tag[1] == 'U') {
+ OU = begin;
+ OU_len = len;
+
+ /* state */
+ } else if (tag[0] == 'S' and tag[1] == 'T') {
+ ST = begin;
+ ST_len = len;
+
+ /* locality */
+ } else if (tag[0] == 'L' and tag[1] == '\0') {
+ L = begin;
+ L_len = len;
+
+ /* email */
+ } else if (tag[0] == 'R' and tag[1] == '\0') {
+ R = begin;
+ R_len = len;
+ }
+
+ /* set tag poiner to begin */
+ tag_sp = tag;
+
+ /* is at end? */
+ if (*sp == '\0' or *(sp +1) == '\0')
+ break;
+ } else {
+ ++len;
+ }
+ }
+
+ /* make saver */
+ if (*sp == '\0')
+ break;
+ } /* end for */
+
+ /* country */
+ if (C != NULL) {
+ oid[2] = X520_COUNTRY;
+ if ((ret = x509write_add_name(node, oid, 3, C, C_len,
+ ASN1_PRINTABLE_STRING)) != 0)
+ return ret;
+ }
+
+ /* state */
+ if (ST != NULL) {
+ oid[2] = X520_STATE;
+ if ((ret = x509write_add_name(node, oid, 3, ST, ST_len,
+ ASN1_PRINTABLE_STRING)) != 0)
+ return ret;
+ }
+
+ /* locality */
+ if (L != NULL) {
+ oid[2] = X520_LOCALITY;
+ if ((ret = x509write_add_name(node, oid, 3, L, L_len,
+ ASN1_PRINTABLE_STRING)) != 0)
+ return ret;
+ }
+
+ /* organization */
+ if (O != NULL) {
+ oid[2] = X520_ORGANIZATION;
+ if ((ret = x509write_add_name(node, oid, 3, O, O_len,
+ ASN1_PRINTABLE_STRING)) != 0)
+ return ret;
+ }
+
+ /* organisation unit */
+ if (OU != NULL) {
+ oid[2] = X520_ORG_UNIT;
+ if ((ret = x509write_add_name(node, oid, 3, OU, OU_len,
+ ASN1_PRINTABLE_STRING)) != 0)
+ return ret;
+ }
+
+ /* common name */
+ if (CN != NULL) {
+ oid[2] = X520_COMMON_NAME;
+ if ((ret = x509write_add_name(node, oid, 3, CN, CN_len,
+ ASN1_PRINTABLE_STRING)) != 0)
+ return ret;
+ }
+
+ /* email */
+ if (R != NULL) {
+ if ((ret = x509write_add_name(node, (unsigned char*)OID_PKCS9_EMAIL,
+ 9, R, R_len, ASN1_IA5_STRING)) != 0)
+ return ret;
+ }
+
+ if ((asn1_append_tag(node, ASN1_CONSTRUCTED | ASN1_SEQUENCE)) != 0)
+ return ret;
+
+ return 0;
+}
+
+/*
+ * Copy raw data from orginal ca to node
+ */
+static int x509write_copy_from_raw(x509_node *node, x509_buf *raw)
+{
+ if (x509write_realloc_node(node, raw->len) != 0)
+ return 1;
+
+ memcpy(node->p, raw->p, (size_t)raw->len);
+ if ((node->p += raw->len -1) != node->end)
+ return POLARSSL_ERR_X509_POINT_ERROR;
+
+ return 0;
+}
+
+/*
+ * Add the issuer
+ */
+
+int x509write_add_issuer(x509_raw *crt, unsigned char *issuer)
+{
+ return x509write_parse_names(&crt->issuer, issuer);
+}
+
+/*
+ * Add the subject
+ */
+int x509write_add_subject(x509_raw *crt, unsigned char *subject)
+{
+ return x509write_parse_names(&crt->subject, subject);
+}
+
+/*
+ * Copy issuer line from another cert to issuer
+ */
+int x509write_copy_issuer(x509_raw *crt, x509_cert *from_crt)
+{
+ return x509write_copy_from_raw(&crt->issuer, &from_crt->issuer_raw);
+}
+
+/*
+ * Copy subject line from another cert
+ */
+int x509write_copy_subject(x509_raw *crt, x509_cert *from_crt)
+{
+ return x509write_copy_from_raw(&crt->subject, &from_crt->subject_raw);
+}
+
+/*
+ * Copy subject line form antoher cert into issuer
+ */
+int x509write_copy_issuer_form_subject(x509_raw *crt,
+ x509_cert *from_crt)
+{
+ return x509write_copy_from_raw(&crt->issuer, &from_crt->subject_raw);
+}
+
+/*
+ * Copy issuer line from another cert into subject
+ */
+int x509write_copy_subject_from_issuer(x509_raw *crt,
+ x509_cert * from_crt)
+{
+ return x509write_copy_from_raw(&crt->subject, &from_crt->issuer_raw);
+}
+
+/*
+ * Validity ::= SEQUENCE {
+ * notBefore Time,
+ * notAfter Time }
+ *
+ * Time ::= CHOICE {
+ * utcTime UTCTime,
+ * generalTime GeneralizedTime }
+ */
+/* TODO: No handle GeneralizedTime! */
+int x509write_add_validity(x509_raw *chain, unsigned char *befor,
+ unsigned char *after)
+{
+ int ret;
+
+ x509_node *node = &chain->validity;
+
+ /* notBefore */
+ if ((ret = asn1_add_date_utc(befor, node)) != 0)
+ return ret;
+
+ /* notAfter */
+ if ((ret = asn1_add_date_utc(after, node)) != 0)
+ return ret;
+
+ if ((ret = asn1_append_tag(node, ASN1_CONSTRUCTED | ASN1_SEQUENCE)) != 0)
+ return ret;
+
+ return 0;
+}
+
+/*
+ * make hash from tbs and sign that with private key
+ */
+static int x509write_make_sign(x509_raw *chain, rsa_context *privkey)
+{
+ int ret;
+ unsigned char hash[20], *sign;
+ size_t sign_len = (size_t) mpi_size(&privkey->N);
+
+ /* make hash */
+ sha1(chain->tbs.data, chain->tbs.len, hash);
+
+ /* create sign */
+ sign = (unsigned char *) malloc(sign_len);
+ if (sign == NULL)
+ return 1;
+
+ if ((ret = rsa_pkcs1_sign(privkey, NULL, NULL, RSA_PRIVATE, SIG_RSA_SHA1, 20, hash,
+ sign)) != 0)
+ return ret;
+
+ if ((ret = asn1_add_obj(sign, sign_len, ASN1_BIT_STRING,
+ &chain->sign)) != 0)
+ return ret;
+
+ /*
+ * AlgorithmIdentifier ::= SEQUENCE {
+ * algorithm OBJECT IDENTIFIER,
+ * parameters ANY DEFINED BY algorithm OPTIONAL }
+ */
+ return asn1_add_oid(&chain->signalg, (unsigned char*)OID_PKCS1_SHA1, 9,
+ ASN1_CONSTRUCTED | ASN1_SEQUENCE, ASN1_NULL,
+ (unsigned char*)"", 0);
+}
+
+/*
+ * Create a self signed certificate
+ */
+int x509write_create_sign(x509_raw *chain, rsa_context *privkey)
+{
+ int ret, serial;
+
+ /*
+ * Version ::= INTEGER { v1(0), v2(1), v3(2) }
+ */
+ if ((ret = asn1_add_int(2, &chain->version)) != 0)
+ return ret;
+
+ if ((ret = asn1_append_tag(&chain->version, ASN1_CONTEXT_SPECIFIC |
+ ASN1_CONSTRUCTED)) != 0)
+ return ret;
+
+
+ /*
+ * CertificateSerialNumber ::= INTEGER
+ */
+ srand((unsigned int) time(NULL));
+ serial = rand();
+ if ((ret = asn1_add_int(serial, &chain->serial)) != 0)
+ return ret;
+
+ /*
+ * AlgorithmIdentifier ::= SEQUENCE {
+ * algorithm OBJECT IDENTIFIER,
+ * parameters ANY DEFINED BY algorithm OPTIONAL }
+ */
+ if ((ret = asn1_add_oid(&chain->tbs_signalg,
+ (unsigned char*)OID_PKCS1_SHA1, 9, ASN1_CONSTRUCTED |
+ ASN1_SEQUENCE, ASN1_NULL, (unsigned char*)"", 0)) != 0)
+ return ret;
+
+ /*
+ * Create the tbs
+ */
+ if ((ret = asn1_append_nodes(&chain->tbs, ASN1_CONSTRUCTED |
+ ASN1_SEQUENCE, 7, &chain->version, &chain->serial,
+ &chain->tbs_signalg, &chain->issuer, &chain->validity,
+ &chain->subject, &chain->subpubkey)) != 0)
+ return ret;
+
+ /* make signing */
+ if ((ret = x509write_make_sign(chain, privkey)) != 0)
+ return ret;
+
+ /* finishing */
+ if ((ret = asn1_append_nodes(&chain->raw, ASN1_CONSTRUCTED |
+ ASN1_SEQUENCE, 3, &chain->tbs, &chain->signalg,
+ &chain->sign)) != 0)
+ return ret;
+
+ return 0;
+}
+
+int x509write_create_selfsign(x509_raw *chain, rsa_context *privkey)
+{
+ /*
+ * On self signed certificate are subject and issuer the same
+ */
+ x509write_free_node(&chain->issuer);
+ chain->issuer = chain->subject;
+ return x509write_create_sign(chain, privkey);
+}
+
+/*
+ * CertificationRequestInfo ::= SEQUENCE {
+ * version Version,
+ * subject Name,
+ * subjectPublicKeyInfo SubjectPublicKeyInfo,
+ * attributes [0] IMPLICIT Attributes }
+ *
+ * CertificationRequest ::= SEQUENCE {
+ * certificationRequestInfo CertificationRequestInfo,
+ * signatureAlgorithm SignatureAlgorithmIdentifier,
+ * signature Signature }
+ *
+ * It use chain.serail for attributes!
+ *
+ */
+int x509write_create_csr(x509_raw *chain, rsa_context *privkey)
+{
+ int ret;
+
+ /* version ::= INTEGER */
+ if ((ret = asn1_add_int(0, &chain->version)) != 0)
+ return ret;
+
+ /* write attributes */
+ if ((ret = asn1_add_obj((unsigned char*)"", 0, ASN1_CONTEXT_SPECIFIC |
+ ASN1_CONSTRUCTED, &chain->serial)) != 0)
+ return ret;
+
+ /* create CertificationRequestInfo */
+ if ((ret = asn1_append_nodes(&chain->tbs, ASN1_CONSTRUCTED |
+ ASN1_SEQUENCE, 4, &chain->version, &chain->subject,
+ &chain->subpubkey, &chain->serial)) != 0)
+ return ret;
+
+ /* make signing */
+ if ((ret = x509write_make_sign(chain, privkey)) != 0)
+ return ret;
+
+ /* finish */
+ if ((ret = asn1_append_nodes(&chain->raw, ASN1_CONSTRUCTED | ASN1_SEQUENCE,
+ 3, &chain->tbs, &chain->signalg, &chain->sign)) != 0)
+ return ret;
+
+ return ret;
+}
+
+/*
+ * Free memory
+ */
+void x509write_free_raw(x509_raw *chain)
+{
+ x509write_free_node(&chain->raw);
+ x509write_free_node(&chain->tbs);
+ x509write_free_node(&chain->version);
+ x509write_free_node(&chain->serial);
+ x509write_free_node(&chain->tbs_signalg);
+ x509write_free_node(&chain->issuer);
+ x509write_free_node(&chain->validity);
+ if (chain->subject.data != chain->issuer.data)
+ x509write_free_node(&chain->subject);
+ x509write_free_node(&chain->subpubkey);
+ x509write_free_node(&chain->signalg);
+ x509write_free_node(&chain->sign);
+}
+
+void x509write_init_raw(x509_raw *chain)
+{
+ memset((void *) chain, 0, sizeof(x509_raw));
+}
+/*
* X509 buffer writing functionality
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved