| | 1 | --- include/polarssl/x509.h |
| | 2 | +++ include/polarssl/x509.h |
| | 3 | @@ -429,6 +429,229 @@ |
| | 4 | */ |
| | 5 | int x509_self_test( int verbose ); |
| | 6 | |
| | 7 | +/** |
| | 8 | + * \brief Write a certificate info file |
| | 9 | + * |
| | 10 | + * \param chain points to the raw certificate data |
| | 11 | + * \param path filename to write the certificate to |
| | 12 | + * \param format X509_OUTPUT_DER or X509_OUTPUT_PEM |
| | 13 | + * |
| | 14 | + * \return 0 if successful, or a specific X509 error code |
| | 15 | + */ |
| | 16 | +int x509write_crtfile( x509_raw *chain, |
| | 17 | + unsigned char *path, |
| | 18 | + int format ); |
| | 19 | + |
| | 20 | +/** |
| | 21 | + * \brief Write a certificate signing request message format file |
| | 22 | + * |
| | 23 | + * \param chain points to the raw certificate (with x509write_create_csr) data |
| | 24 | + * \param path filename to write the certificate to |
| | 25 | + * \param format X509_OUTPUT_DER or X509_OUTPUT_PEM |
| | 26 | + * |
| | 27 | + * \return 0 if successful, or a specific X509 error code |
| | 28 | + */ |
| | 29 | +int x509write_csrfile( x509_raw *chain, |
| | 30 | + unsigned char *path, |
| | 31 | + int format ); |
| | 32 | + |
| | 33 | +/* |
| | 34 | + * \brief Write a private RSA key into a file |
| | 35 | + * |
| | 36 | + * \param rsa points to an RSA key |
| | 37 | + * \param path filename to write the key to |
| | 38 | + * \param format X509_OUTPUT_DER or X509_OUTPUT_PEM |
| | 39 | + * |
| | 40 | + * \return 0 if successful, or a specific X509 error code |
| | 41 | + */ |
| | 42 | +int x509write_keyfile( rsa_context *rsa, |
| | 43 | + char *path, |
| | 44 | + int format ); |
| | 45 | + |
| | 46 | +/** |
| | 47 | + * \brief Add a public key to certificate |
| | 48 | + * |
| | 49 | + * \param chain points to the raw certificate data |
| | 50 | + * \param pubkey points to an RSA key |
| | 51 | + * |
| | 52 | + * \return 0 if successful, or a specific X509 error code |
| | 53 | + */ |
| | 54 | +int x509write_add_pubkey( x509_raw *chain, rsa_context *pubkey ); |
| | 55 | + |
| | 56 | +/** |
| | 57 | + * \brief Create x509 subject/issuer field to raw certificate |
| | 58 | + * from string or CA cert. Make string NULL if you will |
| | 59 | + * use the CA copy function or make CA NULL then used |
| | 60 | + * the string parse. |
| | 61 | + * |
| | 62 | + * \param chain points to the raw certificate data |
| | 63 | + * \param names a string that can hold (separete with ";"): |
| | 64 | + * CN=CommonName |
| | 65 | + * -- O=Organization |
| | 66 | + * -- OU=OrgUnit |
| | 67 | + * -- ST=State |
| | 68 | + * -- L=Locality |
| | 69 | + * -- R=Email |
| | 70 | + * -- C=Country |
| | 71 | + * . Make that NULL if you didn't need that. |
| | 72 | + * \param flag flag is X509_ISSUER or X509_SUBJECT that defined |
| | 73 | + * where change |
| | 74 | + * \param ca the certificate for copy data. Make that NULL if you |
| | 75 | + * didn't need that. |
| | 76 | + * \param ca_flag set the ca field from copy to crt |
| | 77 | + * |
| | 78 | + * \return 0 if successful, or a specific X509 error code |
| | 79 | + */ |
| | 80 | +int x509write_add_customize ( x509_raw *crt, |
| | 81 | + unsigned char *names, |
| | 82 | + int flag, |
| | 83 | + x509_cert *ca, |
| | 84 | + int ca_flag ); |
| | 85 | + |
| | 86 | +/** |
| | 87 | +* \brief Add x509 issuer field |
| | 88 | +* |
| | 89 | +* \param chain points to the raw certificate data |
| | 90 | +* \param issuer a string holding (separete with ";"): |
| | 91 | +* CN=CommonName |
| | 92 | +* -- O=Organization |
| | 93 | +* -- OU=OrgUnit |
| | 94 | +* -- ST=State |
| | 95 | +* -- L=Locality |
| | 96 | +* -- R=Email |
| | 97 | +* -- C=Country |
| | 98 | +* . Set this to NULL if not needed. |
| | 99 | +* \return 0 if successful, or a specific X509 error code |
| | 100 | +*/ |
| | 101 | +int x509write_add_issuer( x509_raw *crt, unsigned char *issuer); |
| | 102 | + |
| | 103 | +/** |
| | 104 | + * \brief Add x509 subject field |
| | 105 | + * |
| | 106 | + * \param chain points to the raw certificate data |
| | 107 | + * \param subject a string holding (separete with ";"): |
| | 108 | + * CN=CommonName |
| | 109 | + * -- O=Organization |
| | 110 | + * -- OU=OrgUnit |
| | 111 | + * -- ST=State |
| | 112 | + * -- L=Locality |
| | 113 | + * -- R=Email |
| | 114 | + * -- C=Country |
| | 115 | + * . Set this to NULL if not needed. |
| | 116 | + * \return 0 if successful, or a specific X509 error code |
| | 117 | + */ |
| | 118 | +int x509write_add_subject( x509_raw *crt, unsigned char *subject); |
| | 119 | + |
| | 120 | +/** |
| | 121 | +* \brief Copy x509 issuer field from another certificate |
| | 122 | +* |
| | 123 | +* \param chain points to the raw certificate data |
| | 124 | +* \param from_crt the certificate whose issuer is to be copied. |
| | 125 | +* \return 0 if successful, or a specific X509 error code |
| | 126 | +*/ |
| | 127 | +int x509write_copy_issuer(x509_raw *crt, x509_cert *from_crt); |
| | 128 | + |
| | 129 | +/** |
| | 130 | +* \brief Copy x509 subject field from another certificate |
| | 131 | +* |
| | 132 | +* \param chain points to the raw certificate data |
| | 133 | +* \param from_crt the certificate whose subject is to be copied. |
| | 134 | +* \return 0 if successful, or a specific X509 error code |
| | 135 | +*/ |
| | 136 | +int x509write_copy_subject(x509_raw *crt, x509_cert *from_crt); |
| | 137 | + |
| | 138 | +/** |
| | 139 | +* \brief Copy x509 issuer field from the subject of another certificate |
| | 140 | +* |
| | 141 | +* \param chain points to the raw certificate data |
| | 142 | +* \param from_crt the certificate whose subject is to be copied. |
| | 143 | +* \return 0 if successful, or a specific X509 error code |
| | 144 | +*/ |
| | 145 | +int x509write_copy_issuer_from_subject(x509_raw *crt, x509_cert *from_crt); |
| | 146 | + |
| | 147 | +/** |
| | 148 | +* \brief Copy x509 subject field from the issuer of another certificate |
| | 149 | +* |
| | 150 | +* \param chain points to the raw certificate data |
| | 151 | +* \param from_crt the certificate whose issuer is to be copied. |
| | 152 | +* \return 0 if successful, or a specific X509 error code |
| | 153 | +*/ |
| | 154 | +int x509write_copy_subject_from_issuer(x509_raw *crt, x509_cert *from_crt); |
| | 155 | + |
| | 156 | +/** |
| | 157 | + * \brief Create x509 validity time in UTC |
| | 158 | + * |
| | 159 | + * \param chain points to the raw certificate data |
| | 160 | + * \param before valid not before in format YYYY-MM-DD hh:mm:ss |
| | 161 | + * \param after valid not after in format YYYY-MM-DD hh:mm:ss |
| | 162 | + * |
| | 163 | + * \return 0 if successful, or a specific X509 error code |
| | 164 | + */ |
| | 165 | +int x509write_add_validity( x509_raw *crt, |
| | 166 | + unsigned char *before, |
| | 167 | + unsigned char *after ); |
| | 168 | + |
| | 169 | +/** |
| | 170 | + * \brief Create a self-signed certificate |
| | 171 | + * |
| | 172 | + * \param chain points to the raw certificate data |
| | 173 | + * \param rsa a private key to sign the certificate |
| | 174 | + * |
| | 175 | + * \return 0 if successful, or a specific X509 error code |
| | 176 | + */ |
| | 177 | +int x509write_create_selfsign( x509_raw *crt, rsa_context *raw ); |
| | 178 | + |
| | 179 | +/** |
| | 180 | + * \brief Create a certificate |
| | 181 | + * |
| | 182 | + * \param chain points to the raw certificate data |
| | 183 | + * \param rsa a private key to sign the certificate |
| | 184 | + * |
| | 185 | + * \return 0 if successful, or a specific X509 error code |
| | 186 | + */ |
| | 187 | +int x509write_create_sign( x509_raw *crt, rsa_context *raw ); |
| | 188 | + |
| | 189 | +/** |
| | 190 | + * \brief Create a certificate signing request |
| | 191 | + * |
| | 192 | + * \param chain points to the raw certificate data. Didn't use the |
| | 193 | + * same chain that u have use for certificate. |
| | 194 | + * \param privkey a rsa private key |
| | 195 | + * |
| | 196 | + * \return 0 if successful, or a specific X509 error code |
| | 197 | + */ |
| | 198 | +int x509write_create_csr( x509_raw *chain, rsa_context *privkey ); |
| | 199 | + |
| | 200 | +/** |
| | 201 | + * \brief Serialize an rsa key into DER |
| | 202 | + * |
| | 203 | + * \param rsa a rsa key for output |
| | 204 | + * \param node a x509 node for write into |
| | 205 | + * |
| | 206 | + * \return 0 if successful, or a specific X509 error code |
| | 207 | + */ |
| | 208 | +int x509write_serialize_key( rsa_context *rsa, x509_node *node ); |
| | 209 | + |
| | 210 | +/** |
| | 211 | + * \brief Unallocate all raw certificate data |
| | 212 | + */ |
| | 213 | +void x509write_free_raw( x509_raw *crt ); |
| | 214 | + |
| | 215 | +/** |
| | 216 | + * \brief Allocate all raw certificate data |
| | 217 | + */ |
| | 218 | +void x509write_init_raw( x509_raw *crt ); |
| | 219 | + |
| | 220 | +/** |
| | 221 | + * \brief Unallocate all node certificate data |
| | 222 | + */ |
| | 223 | +void x509write_free_node( x509_node *crt_node ); |
| | 224 | + |
| | 225 | +/** |
| | 226 | + * \brief Allocate all node certificate data |
| | 227 | + */ |
| | 228 | +void x509write_init_node( x509_node *crt_node ); |
| | 229 | + |
| | 230 | #ifdef __cplusplus |
| | 231 | } |
| | 232 | #endif |
| | 233 | --- library/Makefile |
| | 234 | +++ library/Makefile |
| | 235 | @@ -25,7 +25,7 @@ |
| | 236 | sha1.o sha2.o sha4.o \ |
| | 237 | ssl_cli.o ssl_srv.o ssl_tls.o \ |
| | 238 | timing.o x509parse.o xtea.o \ |
| | 239 | - camellia.o |
| | 240 | + camellia.o x509write.o |
| | 241 | |
| | 242 | .SILENT: |
| | 243 | |
| | 244 | --- library/x509write.c |
| | 245 | +++ library/x509write.c |
| | 246 | @@ -0,0 +1,1135 @@ |
| | 247 | +/* |
| | 248 | + * X.509 certificate and private key writing |
| | 249 | + * |
| | 250 | + * Copyright (C) 2006-2007 Pascal Vizeli <pvizeli@yahoo.de> |
| | 251 | + * Modifications (C) 2009 Steven Barth <steven@midlink.org> |
| | 252 | + * |
| | 253 | + * This library is free software; you can redistribute it and/or |
| | 254 | + * modify it under the terms of the GNU Lesser General Public |
| | 255 | + * License, version 2.1 as published by the Free Software Foundation. |
| | 256 | + * |
| | 257 | + * This library is distributed in the hope that it will be useful, |
| | 258 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | 259 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| | 260 | + * Lesser General Public License for more details. |
| | 261 | + * |
| | 262 | + * You should have received a copy of the GNU Lesser General Public |
| | 263 | + * License along with this library; if not, write to the Free Software |
| | 264 | + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
| | 265 | + * MA 02110-1301 USA |
| | 266 | + */ |
| | 267 | +/* |
| | 268 | + * The ITU-T X.509 standard defines a certificat format for PKI. |
| | 269 | + * |
| | 270 | + * http://www.ietf.org/rfc/rfc2459.txt |
| | 271 | + * http://www.ietf.org/rfc/rfc3279.txt |
| | 272 | + * |
| | 273 | + * ftp://ftp.rsasecurity.com/pub/pkcs/ascii/pkcs-1v2.asc |
| | 274 | + * |
| | 275 | + * http://www.itu.int/ITU-T/studygroups/com17/languages/X.680-0207.pdf |
| | 276 | + * http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf |
| | 277 | + * |
| | 278 | + * For CRS: |
| | 279 | + * http://www.faqs.org/rfcs/rfc2314.html |
| | 280 | + */ |
| | 281 | +#include "polarssl/config.h" |
| | 282 | +#include "polarssl/x509.h" |
| | 283 | +#include "polarssl/base64.h" |
| | 284 | +#include "polarssl/sha1.h" |
| | 285 | + |
| | 286 | +#include <string.h> |
| | 287 | +#include <stdlib.h> |
| | 288 | +#include <stdio.h> |
| | 289 | +#include <stdarg.h> |
| | 290 | +#include <time.h> |
| | 291 | + |
| | 292 | +#define and && |
| | 293 | +#define or || |
| | 294 | + |
| | 295 | +#if defined _MSC_VER && !defined snprintf |
| | 296 | +#define snprintf _snprintf |
| | 297 | +#endif |
| | 298 | + |
| | 299 | +static int x509write_realloc_node(x509_node *node, size_t larger); |
| | 300 | +static int x509write_file(x509_node *node, char *path, int format, const char* pem_prolog, const char* pem_epilog); |
| | 301 | + |
| | 302 | +/* |
| | 303 | + * evaluate how mani octet have this integer |
| | 304 | + */ |
| | 305 | +static int asn1_eval_octet(unsigned int digit) |
| | 306 | +{ |
| | 307 | + int i, byte; |
| | 308 | + |
| | 309 | + for (byte = 4, i = 24; i >= 0; i -= 8, --byte) |
| | 310 | + if (((digit >> i) & 0xFF) != 0) |
| | 311 | + return byte; |
| | 312 | + |
| | 313 | + return 0; |
| | 314 | +} |
| | 315 | + |
| | 316 | +/* |
| | 317 | + * write the asn.1 lenght form into p |
| | 318 | + */ |
| | 319 | +static int asn1_add_len(unsigned int size, x509_node *node) |
| | 320 | +{ |
| | 321 | + if (size > 127) { |
| | 322 | + |
| | 323 | + /* long size */ |
| | 324 | + int byte = asn1_eval_octet(size); |
| | 325 | + int i = 0; |
| | 326 | + |
| | 327 | + *(node->p) = (0x80 | byte) & 0xFF; |
| | 328 | + ++node->p; |
| | 329 | + |
| | 330 | + for (i = byte; i > 0; --i) { |
| | 331 | + |
| | 332 | + *(node->p) = (size >> ((i - 1) * 8)) & 0xFF; |
| | 333 | + ++node->p; |
| | 334 | + } |
| | 335 | + |
| | 336 | + } else { |
| | 337 | + |
| | 338 | + /* short size */ |
| | 339 | + *(node->p) = size & 0xFF; |
| | 340 | + if (size != 0) |
| | 341 | + ++node->p; |
| | 342 | + } |
| | 343 | + |
| | 344 | + return 0; |
| | 345 | +} |
| | 346 | + |
| | 347 | +/* |
| | 348 | + * write a ans.1 object into p |
| | 349 | + */ |
| | 350 | +static int asn1_add_obj(unsigned char *value, unsigned int size, int tag, |
| | 351 | + x509_node *node) |
| | 352 | +{ |
| | 353 | + int tl = 2; |
| | 354 | + |
| | 355 | + if (tag == ASN1_BIT_STRING) |
| | 356 | + ++tl; |
| | 357 | + |
| | 358 | + if (size > 127) |
| | 359 | + x509write_realloc_node(node, (size_t) size + tl + |
| | 360 | + asn1_eval_octet(size)); |
| | 361 | + else |
| | 362 | + x509write_realloc_node(node, (size_t) size + tl); |
| | 363 | + |
| | 364 | + if (node->data == NULL) |
| | 365 | + return 1; |
| | 366 | + |
| | 367 | + /* tag */ |
| | 368 | + *(node->p) = tag & 0xFF; |
| | 369 | + ++node->p; |
| | 370 | + |
| | 371 | + /* len */ |
| | 372 | + if (tag == ASN1_BIT_STRING) { |
| | 373 | + asn1_add_len((unsigned int) size + 1, node); |
| | 374 | + *(node->p) = 0x00; |
| | 375 | + ++node->p; |
| | 376 | + } else { |
| | 377 | + asn1_add_len((unsigned int) size, node); |
| | 378 | + } |
| | 379 | + |
| | 380 | + /* value */ |
| | 381 | + if (size > 0) { |
| | 382 | + |
| | 383 | + memcpy(node->p, value, (size_t) size); |
| | 384 | + if ((node->p += size -1) != node->end) |
| | 385 | + return POLARSSL_ERR_X509_POINT_ERROR; |
| | 386 | + } else { |
| | 387 | + /* make nothing -> NULL */ |
| | 388 | + } |
| | 389 | + |
| | 390 | + return 0; |
| | 391 | +} |
| | 392 | + |
| | 393 | +/* |
| | 394 | + * write a asn.1 conform integer object |
| | 395 | + */ |
| | 396 | +static int asn1_add_int(signed int value, x509_node *node) |
| | 397 | +{ |
| | 398 | + signed int i = 0, neg = 1; |
| | 399 | + unsigned int byte, u_val = 0, tmp_val = 0; |
| | 400 | + |
| | 401 | + /* if negate? */ |
| | 402 | + if (value < 0) { |
| | 403 | + neg = -1; |
| | 404 | + u_val = ~value; |
| | 405 | + } else { |
| | 406 | + u_val = value; |
| | 407 | + } |
| | 408 | + |
| | 409 | + byte = asn1_eval_octet(u_val); |
| | 410 | + /* 0 isn't NULL */ |
| | 411 | + if (byte == 0) |
| | 412 | + byte = 1; |
| | 413 | + |
| | 414 | + /* ASN.1 integer is signed! */ |
| | 415 | + if (byte < 4 and ((u_val >> ((byte -1) * 8)) & 0xFF) == 0x80) |
| | 416 | + byte += 1; |
| | 417 | + |
| | 418 | + if (x509write_realloc_node(node, (size_t) byte + 2) != 0) |
| | 419 | + return 1; |
| | 420 | + |
| | 421 | + /* tag */ |
| | 422 | + *(node->p) = ASN1_INTEGER; |
| | 423 | + ++node->p; |
| | 424 | + |
| | 425 | + /* len */ |
| | 426 | + asn1_add_len(byte, node); |
| | 427 | + |
| | 428 | + /* value */ |
| | 429 | + for (i = byte; i > 0; --i) { |
| | 430 | + |
| | 431 | + tmp_val = (u_val >> ((i - 1) * 8)) & 0xFF; |
| | 432 | + if (neg == 1) |
| | 433 | + *(node->p) = tmp_val; |
| | 434 | + else |
| | 435 | + *(node->p) = ~tmp_val; |
| | 436 | + |
| | 437 | + if (i > 1) |
| | 438 | + ++node->p; |
| | 439 | + } |
| | 440 | + |
| | 441 | + if (node->p != node->end) |
| | 442 | + return POLARSSL_ERR_X509_POINT_ERROR; |
| | 443 | + |
| | 444 | + return 0; |
| | 445 | +} |
| | 446 | + |
| | 447 | +/* |
| | 448 | + * write a asn.1 conform mpi object |
| | 449 | + */ |
| | 450 | +static int asn1_add_mpi(mpi *value, int tag, x509_node *node) |
| | 451 | +{ |
| | 452 | + size_t size = (mpi_msb(value) / 8) + 1; |
| | 453 | + unsigned char *buf; |
| | 454 | + int buf_len = (int) size, tl = 2; |
| | 455 | + |
| | 456 | + if (tag == ASN1_BIT_STRING) |
| | 457 | + ++tl; |
| | 458 | + |
| | 459 | + if (size > 127) |
| | 460 | + x509write_realloc_node(node, size + (size_t) tl + |
| | 461 | + asn1_eval_octet((unsigned int)size)); |
| | 462 | + else |
| | 463 | + x509write_realloc_node(node, size + (size_t) tl); |
| | 464 | + |
| | 465 | + if (node->data == NULL) |
| | 466 | + return 1; |
| | 467 | + |
| | 468 | + buf = (unsigned char*) malloc(size); |
| | 469 | + if (mpi_write_binary(value, buf, buf_len) != 0) |
| | 470 | + return POLARSSL_ERR_MPI_BUFFER_TOO_SMALL; |
| | 471 | + |
| | 472 | + /* tag */ |
| | 473 | + *(node->p) = tag & 0xFF; |
| | 474 | + ++node->p; |
| | 475 | + |
| | 476 | + /* len */ |
| | 477 | + if (tag == ASN1_BIT_STRING) { |
| | 478 | + asn1_add_len((unsigned int) size + 1, node); |
| | 479 | + *(node->p) = 0x00; |
| | 480 | + ++node->p; |
| | 481 | + } else { |
| | 482 | + asn1_add_len((unsigned int) size, node); |
| | 483 | + } |
| | 484 | + |
| | 485 | + /* value */ |
| | 486 | + memcpy(node->p, buf, size); |
| | 487 | + free(buf); |
| | 488 | + |
| | 489 | + if ((node->p += (int) size -1) != node->end) |
| | 490 | + return POLARSSL_ERR_X509_POINT_ERROR; |
| | 491 | + |
| | 492 | + return 0; |
| | 493 | +} |
| | 494 | + |
| | 495 | +/* |
| | 496 | + * write a node into asn.1 conform object |
| | 497 | + */ |
| | 498 | +static int asn1_append_tag(x509_node *node, int tag) |
| | 499 | +{ |
| | 500 | + int tl = 2; |
| | 501 | + |
| | 502 | + x509_node tmp; |
| | 503 | + x509write_init_node(&tmp); |
| | 504 | + |
| | 505 | + if (tag == ASN1_BIT_STRING) |
| | 506 | + ++tl; |
| | 507 | + |
| | 508 | + if (node->len > 127) |
| | 509 | + x509write_realloc_node(&tmp, node->len + (size_t) tl + |
| | 510 | + asn1_eval_octet((unsigned int)node->len)); |
| | 511 | + else |
| | 512 | + x509write_realloc_node(&tmp, node->len + (size_t) tl); |
| | 513 | + |
| | 514 | + if (tmp.data == NULL) { |
| | 515 | + x509write_free_node(&tmp); |
| | 516 | + return 1; |
| | 517 | + } |
| | 518 | + |
| | 519 | + /* tag */ |
| | 520 | + *(tmp.p) = tag & 0xFF; |
| | 521 | + ++tmp.p; |
| | 522 | + |
| | 523 | + /* len */ |
| | 524 | + if (tag == ASN1_BIT_STRING) { |
| | 525 | + asn1_add_len((unsigned int) node->len + 1, &tmp); |
| | 526 | + *(tmp.p) = 0x00; |
| | 527 | + ++tmp.p; |
| | 528 | + } else { |
| | 529 | + asn1_add_len((unsigned int) node->len, &tmp); |
| | 530 | + } |
| | 531 | + |
| | 532 | + /* value */ |
| | 533 | + memcpy(tmp.p, node->data, node->len); |
| | 534 | + |
| | 535 | + /* good? */ |
| | 536 | + if ((tmp.p += (int) node->len -1) != tmp.end) { |
| | 537 | + x509write_free_node(&tmp); |
| | 538 | + return POLARSSL_ERR_X509_POINT_ERROR; |
| | 539 | + } |
| | 540 | + |
| | 541 | + free(node->data); |
| | 542 | + node->data = tmp.data; |
| | 543 | + node->p = tmp.p; |
| | 544 | + node->end = tmp.end; |
| | 545 | + node->len = tmp.len; |
| | 546 | + |
| | 547 | + return 0; |
| | 548 | +} |
| | 549 | + |
| | 550 | +/* |
| | 551 | + * write nodes into a asn.1 object |
| | 552 | + */ |
| | 553 | +static int asn1_append_nodes(x509_node *node, int tag, int anz, ...) |
| | 554 | +{ |
| | 555 | + va_list ap; |
| | 556 | + size_t size = 0; |
| | 557 | + x509_node *tmp; |
| | 558 | + int count; |
| | 559 | + |
| | 560 | + va_start(ap, anz); |
| | 561 | + count = anz; |
| | 562 | + |
| | 563 | + while (count--) { |
| | 564 | + |
| | 565 | + tmp = va_arg(ap, x509_node*); |
| | 566 | + if (tmp->data != NULL) |
| | 567 | + size += tmp->len; |
| | 568 | + } |
| | 569 | + |
| | 570 | + if ( size > 127) { |
| | 571 | + if (x509write_realloc_node(node, size + (size_t) 2 + |
| | 572 | + asn1_eval_octet(size)) != 0) |
| | 573 | + return 1; |
| | 574 | + } else { |
| | 575 | + if (x509write_realloc_node(node, size + (size_t) 2) != 0) |
| | 576 | + return 1; |
| | 577 | + } |
| | 578 | + |
| | 579 | + /* tag */ |
| | 580 | + *(node->p) = tag & 0xFF; |
| | 581 | + ++node->p; |
| | 582 | + |
| | 583 | + /* len */ |
| | 584 | + asn1_add_len(size, node); |
| | 585 | + |
| | 586 | + /* value */ |
| | 587 | + va_start(ap, anz); |
| | 588 | + count = anz; |
| | 589 | + |
| | 590 | + while (count--) { |
| | 591 | + |
| | 592 | + tmp = va_arg(ap, x509_node*); |
| | 593 | + if (tmp->data != NULL) { |
| | 594 | + |
| | 595 | + memcpy(node->p, tmp->data, tmp->len); |
| | 596 | + if ((node->p += (int) tmp->len -1) != node->end) |
| | 597 | + ++node->p; |
| | 598 | + } |
| | 599 | + } |
| | 600 | + |
| | 601 | + va_end(ap); |
| | 602 | + return 0; |
| | 603 | +} |
| | 604 | + |
| | 605 | +/* |
| | 606 | + * write a ASN.1 conform object identifiere include a "tag" |
| | 607 | + */ |
| | 608 | +static int asn1_add_oid(x509_node *node, unsigned char *oid, size_t len, |
| | 609 | + int tag, int tag_val, unsigned char *value, size_t val_len) |
| | 610 | +{ |
| | 611 | + int ret; |
| | 612 | + x509_node tmp; |
| | 613 | + |
| | 614 | + x509write_init_node(&tmp); |
| | 615 | + |
| | 616 | + /* OBJECT IDENTIFIER */ |
| | 617 | + if ((ret = asn1_add_obj(oid, len, ASN1_OID, &tmp)) != 0) { |
| | 618 | + x509write_free_node(&tmp); |
| | 619 | + return ret; |
| | 620 | + } |
| | 621 | + |
| | 622 | + /* value */ |
| | 623 | + if ((ret = asn1_add_obj(value, val_len, tag_val, &tmp)) != 0) { |
| | 624 | + x509write_free_node(&tmp); |
| | 625 | + return ret; |
| | 626 | + } |
| | 627 | + |
| | 628 | + /* SET/SEQUENCE */ |
| | 629 | + if ((ret = asn1_append_nodes(node, tag, 1, &tmp)) != 0) { |
| | 630 | + x509write_free_node(&tmp); |
| | 631 | + return ret; |
| | 632 | + } |
| | 633 | + |
| | 634 | + x509write_free_node(&tmp); |
| | 635 | + return 0; |
| | 636 | +} |
| | 637 | + |
| | 638 | +/* |
| | 639 | + * utcTime UTCTime |
| | 640 | + */ |
| | 641 | +static int asn1_add_date_utc(unsigned char *time, x509_node *node) |
| | 642 | +{ |
| | 643 | + unsigned char date[13], *sp; |
| | 644 | + x509_time xtime; |
| | 645 | + int ret; |
| | 646 | + |
| | 647 | + sscanf((char*)time, "%d-%d-%d %d:%d:%d", &xtime.year, &xtime.mon, |
| | 648 | + &xtime.day, &xtime.hour, &xtime.min, &xtime.sec); |
| | 649 | + |
| | 650 | + /* convert to YY */ |
| | 651 | + if (xtime.year > 2000) |
| | 652 | + xtime.year -= 2000; |
| | 653 | + else |
| | 654 | + xtime.year -= 1900; |
| | 655 | + |
| | 656 | + snprintf((char*)date, 13, "%2d%2d%2d%2d%2d%2d", xtime.year, xtime.mon, xtime.day, |
| | 657 | + xtime.hour, xtime.min, xtime.sec); |
| | 658 | + |
| | 659 | + /* replace ' ' to '0' */ |
| | 660 | + for (sp = date; *sp != '\0'; ++sp) |
| | 661 | + if (*sp == '\x20') |
| | 662 | + *sp = '\x30'; |
| | 663 | + |
| | 664 | + date[12] = 'Z'; |
| | 665 | + |
| | 666 | + if ((ret = asn1_add_obj(date, 13, ASN1_UTC_TIME, node)) != 0) |
| | 667 | + return ret; |
| | 668 | + |
| | 669 | + return 0; |
| | 670 | +} |
| | 671 | + |
| | 672 | +/* |
| | 673 | + * serialize an rsa key into DER |
| | 674 | + */ |
| | 675 | + |
| | 676 | +int x509write_serialize_key(rsa_context *rsa, x509_node *node) |
| | 677 | +{ |
| | 678 | + int ret = 0; |
| | 679 | + x509write_init_node(node); |
| | 680 | + |
| | 681 | + /*Â vers, n, e, d, p, q, dp, dq, pq */ |
| | 682 | + if ((ret = asn1_add_int(rsa->ver, node)) != 0) |
| | 683 | + return ret; |
| | 684 | + if ((ret = asn1_add_mpi(&rsa->N, ASN1_INTEGER, node)) != 0) |
| | 685 | + return ret; |
| | 686 | + if ((ret = asn1_add_mpi(&rsa->E, ASN1_INTEGER, node)) != 0) |
| | 687 | + return ret; |
| | 688 | + if ((ret = asn1_add_mpi(&rsa->D, ASN1_INTEGER, node)) != 0) |
| | 689 | + return ret; |
| | 690 | + if ((ret = asn1_add_mpi(&rsa->P, ASN1_INTEGER, node)) != 0) |
| | 691 | + return ret; |
| | 692 | + if ((ret = asn1_add_mpi(&rsa->Q, ASN1_INTEGER, node)) != 0) |
| | 693 | + return ret; |
| | 694 | + if ((ret = asn1_add_mpi(&rsa->DP, ASN1_INTEGER, node)) != 0) |
| | 695 | + return ret; |
| | 696 | + if ((ret = asn1_add_mpi(&rsa->DQ, ASN1_INTEGER, node)) != 0) |
| | 697 | + return ret; |
| | 698 | + if ((ret = asn1_add_mpi(&rsa->QP, ASN1_INTEGER, node)) != 0) |
| | 699 | + return ret; |
| | 700 | + if ((ret = asn1_append_tag(node, ASN1_CONSTRUCTED | ASN1_SEQUENCE)) != 0) |
| | 701 | + return ret; |
| | 702 | + |
| | 703 | + return 0; |
| | 704 | +} |
| | 705 | + |
| | 706 | +/* |
| | 707 | + * write a der/pem encoded rsa private key into a file |
| | 708 | + */ |
| | 709 | +int x509write_keyfile(rsa_context *rsa, char *path, int out_flag) |
| | 710 | +{ |
| | 711 | + int ret = 0; |
| | 712 | + const char key_beg[] = "-----BEGIN RSA PRIVATE KEY-----\n", |
| | 713 | + key_end[] = "-----END RSA PRIVATE KEY-----\n"; |
| | 714 | + x509_node node; |
| | 715 | + |
| | 716 | + x509write_init_node(&node); |
| | 717 | + if ((ret = x509write_serialize_key(rsa,&node)) != 0) { |
| | 718 | + x509write_free_node(&node); |
| | 719 | + return ret; |
| | 720 | + } |
| | 721 | + |
| | 722 | + ret = x509write_file(&node,path,out_flag,key_beg,key_end); |
| | 723 | + x509write_free_node(&node); |
| | 724 | + |
| | 725 | + return ret; |
| | 726 | +} |
| | 727 | + |
| | 728 | + |
| | 729 | +/* |
| | 730 | + * reasize the memory for node |
| | 731 | + */ |
| | 732 | +static int x509write_realloc_node(x509_node *node, size_t larger) |
| | 733 | +{ |
| | 734 | + /* init len */ |
| | 735 | + if (node->data == NULL) { |
| | 736 | + node->len = 0; |
| | 737 | + node->data = malloc(larger); |
| | 738 | + if(node->data == NULL) |
| | 739 | + return 1; |
| | 740 | + } else { |
| | 741 | + /* realloc memory */ |
| | 742 | + if ((node->data = realloc(node->data, node->len + larger)) == NULL) |
| | 743 | + return 1; |
| | 744 | + } |
| | 745 | + |
| | 746 | + /* init pointer */ |
| | 747 | + node->p = &node->data[node->len]; |
| | 748 | + node->len += larger; |
| | 749 | + node->end = &node->data[node->len -1]; |
| | 750 | + |
| | 751 | + return 0; |
| | 752 | +} |
| | 753 | + |
| | 754 | +/* |
| | 755 | + * init node |
| | 756 | + */ |
| | 757 | +void x509write_init_node(x509_node *node) |
| | 758 | +{ |
| | 759 | + memset(node, 0, sizeof(x509_node)); |
| | 760 | +} |
| | 761 | + |
| | 762 | +/* |
| | 763 | + * clean memory |
| | 764 | + */ |
| | 765 | +void x509write_free_node(x509_node *node) |
| | 766 | +{ |
| | 767 | + if (node->data != NULL) |
| | 768 | + free(node->data); |
| | 769 | + node->p = NULL; |
| | 770 | + node->end = NULL; |
| | 771 | + node->len = 0; |
| | 772 | +} |
| | 773 | + |
| | 774 | +/* |
| | 775 | + * write a x509 certificate into file |
| | 776 | + */ |
| | 777 | +int x509write_crtfile(x509_raw *chain, unsigned char *path, int out_flag) |
| | 778 | +{ |
| | 779 | + const char cer_beg[] = "-----BEGIN CERTIFICATE-----\n", |
| | 780 | + cer_end[] = "-----END CERTIFICATE-----\n"; |
| | 781 | + |
| | 782 | + return x509write_file(&chain->raw, (char*)path, out_flag, cer_beg, cer_end); |
| | 783 | +} |
| | 784 | + |
| | 785 | +/* |
| | 786 | + * write a x509 certificate into file |
| | 787 | + */ |
| | 788 | +int x509write_csrfile(x509_raw *chain, unsigned char *path, int out_flag) |
| | 789 | +{ |
| | 790 | + const char cer_beg[] = "-----BEGIN CERTIFICATE REQUEST-----\n", |
| | 791 | + cer_end[] = "-----END CERTIFICATE REQUEST-----\n"; |
| | 792 | + |
| | 793 | + return x509write_file(&chain->raw, (char*)path, out_flag, cer_beg, cer_end); |
| | 794 | +} |
| | 795 | + |
| | 796 | +/* |
| | 797 | + * write an x509 file |
| | 798 | + */ |
| | 799 | +static int x509write_file(x509_node *node, char *path, int format, |
| | 800 | + const char* pem_prolog, const char* pem_epilog) |
| | 801 | +{ |
| | 802 | + FILE *ofstream; |
| | 803 | + int is_err = 1, buf_len, i, n; |
| | 804 | + char* base_buf; |
| | 805 | + |
| | 806 | + if ((ofstream = fopen(path, "wb")) == NULL) |
| | 807 | + return 1; |
| | 808 | + |
| | 809 | + switch (format) { |
| | 810 | + case X509_OUTPUT_DER: |
| | 811 | + if (fwrite(node->data, 1, node->len, ofstream) |
| | 812 | + != node->len) |
| | 813 | + is_err = -1; |
| | 814 | + break; |
| | 815 | + case X509_OUTPUT_PEM: |
| | 816 | + if (fprintf(ofstream,pem_prolog)<0) { |
| | 817 | + is_err = -1; |
| | 818 | + break; |
| | 819 | + } |
| | 820 | + |
| | 821 | + buf_len = node->len << 1; |
| | 822 | + base_buf = (char*) malloc((size_t)buf_len); |
| | 823 | + memset(base_buf,0,buf_len); |
| | 824 | + if (base64_encode(base_buf, &buf_len, node->data, |
| | 825 | + (int) node->len) != 0) { |
| | 826 | + is_err = -1; |
| | 827 | + break; |
| | 828 | + } |
| | 829 | + |
| | 830 | + n=strlen(base_buf); |
| | 831 | + for(i=0;i<n;i+=64) { |
| | 832 | + fprintf(ofstream,"%.64s\n",&base_buf[i]); |
| | 833 | + } |
| | 834 | + |
| | 835 | + if (fprintf(ofstream, pem_epilog)<0) { |
| | 836 | + is_err = -1; |
| | 837 | + break; |
| | 838 | + } |
| | 839 | + |
| | 840 | + free(base_buf); |
| | 841 | + } |
| | 842 | + |
| | 843 | + fclose(ofstream); |
| | 844 | + |
| | 845 | + if (is_err == -1) |
| | 846 | + return 1; |
| | 847 | + |
| | 848 | + return 0; |
| | 849 | +} |
| | 850 | + |
| | 851 | + |
| | 852 | +/* |
| | 853 | + * add the owner public key to x509 certificate |
| | 854 | + */ |
| | 855 | +int x509write_add_pubkey(x509_raw *chain, rsa_context *pubkey) |
| | 856 | +{ |
| | 857 | + x509_node n_tmp, n_tmp2, *node; |
| | 858 | + int ret; |
| | 859 | + |
| | 860 | + node = &chain->subpubkey; |
| | 861 | + |
| | 862 | + x509write_init_node(&n_tmp); |
| | 863 | + x509write_init_node(&n_tmp2); |
| | 864 | + |
| | 865 | + /* |
| | 866 | + * RSAPublicKey ::= SEQUENCE { |
| | 867 | + * modulus INTEGER, -- n |
| | 868 | + * publicExponent INTEGER -- e |
| | 869 | + * } |
| | 870 | + */ |
| | 871 | + if ((ret = asn1_add_mpi(&pubkey->N, ASN1_INTEGER, &n_tmp)) != 0) { |
| | 872 | + x509write_free_node(&n_tmp); |
| | 873 | + x509write_free_node(&n_tmp2); |
| | 874 | + return ret; |
| | 875 | + } |
| | 876 | + if ((ret = asn1_add_mpi(&pubkey->E, ASN1_INTEGER, &n_tmp)) != 0) { |
| | 877 | + x509write_free_node(&n_tmp); |
| | 878 | + x509write_free_node(&n_tmp2); |
| | 879 | + return ret; |
| | 880 | + } |
| | 881 | + if ((ret = asn1_append_tag(&n_tmp, ASN1_CONSTRUCTED | ASN1_SEQUENCE)) |
| | 882 | + != 0) { |
| | 883 | + x509write_free_node(&n_tmp); |
| | 884 | + x509write_free_node(&n_tmp2); |
| | 885 | + return ret; |
| | 886 | + } |
| | 887 | + |
| | 888 | + /* |
| | 889 | + * SubjectPublicKeyInfo ::= SEQUENCE { |
| | 890 | + * algorithm AlgorithmIdentifier, |
| | 891 | + * subjectPublicKey BIT STRING } |
| | 892 | + */ |
| | 893 | + if ((ret = asn1_append_tag(&n_tmp, ASN1_BIT_STRING)) != 0) { |
| | 894 | + x509write_free_node(&n_tmp); |
| | 895 | + x509write_free_node(&n_tmp2); |
| | 896 | + return ret; |
| | 897 | + } |
| | 898 | + if ((ret = asn1_add_oid(&n_tmp2, (unsigned char*)OID_PKCS1_RSA, 9, |
| | 899 | + ASN1_CONSTRUCTED | ASN1_SEQUENCE, ASN1_NULL, |
| | 900 | + (unsigned char *)"", 0)) != 0) { |
| | 901 | + x509write_free_node(&n_tmp); |
| | 902 | + x509write_free_node(&n_tmp2); |
| | 903 | + return ret; |
| | 904 | + } |
| | 905 | + |
| | 906 | + if ((ret = asn1_append_nodes(node, ASN1_CONSTRUCTED | ASN1_SEQUENCE, 2, |
| | 907 | + &n_tmp2, &n_tmp))) { |
| | 908 | + x509write_free_node(&n_tmp); |
| | 909 | + x509write_free_node(&n_tmp2); |
| | 910 | + return ret; |
| | 911 | + } |
| | 912 | + |
| | 913 | + x509write_free_node(&n_tmp); |
| | 914 | + x509write_free_node(&n_tmp2); |
| | 915 | + return 0; |
| | 916 | +} |
| | 917 | + |
| | 918 | +/* |
| | 919 | + * RelativeDistinguishedName ::= |
| | 920 | + * SET OF AttributeTypeAndValue |
| | 921 | + * |
| | 922 | + * AttributeTypeAndValue ::= SEQUENCE { |
| | 923 | + * type AttributeType, |
| | 924 | + * value AttributeValue } |
| | 925 | + */ |
| | 926 | +static int x509write_add_name(x509_node *node, unsigned char *oid, |
| | 927 | + unsigned int oid_len, unsigned char *value, int len, int value_tag) |
| | 928 | +{ |
| | 929 | + int ret; |
| | 930 | + x509_node n_tmp; |
| | 931 | + |
| | 932 | + x509write_init_node(&n_tmp); |
| | 933 | + |
| | 934 | + if ((ret = asn1_add_oid(&n_tmp, oid, oid_len, |
| | 935 | + ASN1_CONSTRUCTED | ASN1_SEQUENCE, value_tag, |
| | 936 | + value, len))) { |
| | 937 | + x509write_free_node(&n_tmp); |
| | 938 | + return ret; |
| | 939 | + } |
| | 940 | + |
| | 941 | + if ((asn1_append_nodes(node, ASN1_CONSTRUCTED | ASN1_SET, 1, &n_tmp)) |
| | 942 | + != 0) { |
| | 943 | + x509write_free_node(&n_tmp); |
| | 944 | + return ret; |
| | 945 | + } |
| | 946 | + |
| | 947 | + x509write_free_node(&n_tmp); |
| | 948 | + return 0; |
| | 949 | +} |
| | 950 | + |
| | 951 | +/* |
| | 952 | + * Parse the name string and add to node |
| | 953 | + */ |
| | 954 | +static int x509write_parse_names(x509_node *node, unsigned char *names) |
| | 955 | +{ |
| | 956 | + unsigned char *sp, *begin = NULL; |
| | 957 | + unsigned char oid[3] = OID_X520, tag[4], *tag_sp = tag; |
| | 958 | + unsigned char *C = NULL, *CN = NULL, *O = NULL, *OU = NULL, |
| | 959 | + *ST = NULL, *L = NULL, *R = NULL; |
| | 960 | + int C_len = 0, CN_len = 0, O_len = 0, OU_len = 0, ST_len = 0, |
| | 961 | + L_len = 0, R_len = 0; |
| | 962 | + int ret = 0, is_tag = 1, is_begin = -1, len = 0; |
| | 963 | + |
| | 964 | + |
| | 965 | + for (sp = names; ; ++sp) { |
| | 966 | + |
| | 967 | + /* filter tag */ |
| | 968 | + if (is_tag == 1) { |
| | 969 | + |
| | 970 | + if (tag_sp == &tag[3]) |
| | 971 | + return POLARSSL_ERR_X509_VALUE_TO_LENGTH; |
| | 972 | + |
| | 973 | + /* is tag end? */ |
| | 974 | + if (*sp == '=') { |
| | 975 | + is_tag = -1; |
| | 976 | + *tag_sp = '\0'; |
| | 977 | + is_begin = 1; |
| | 978 | + /* set len 0 (reset) */ |
| | 979 | + len = 0; |
| | 980 | + } else { |
| | 981 | + /* tag hasn't ' '! */ |
| | 982 | + if (*sp != ' ') { |
| | 983 | + *tag_sp = *sp; |
| | 984 | + ++tag_sp; |
| | 985 | + } |
| | 986 | + } |
| | 987 | + /* filter value */ |
| | 988 | + } else { |
| | 989 | + |
| | 990 | + /* set pointer of value begin */ |
| | 991 | + if (is_begin == 1) { |
| | 992 | + begin = sp; |
| | 993 | + is_begin = -1; |
| | 994 | + } |
| | 995 | + |
| | 996 | + /* is value at end? */ |
| | 997 | + if (*sp == ';' or *sp == '\0') { |
| | 998 | + is_tag = 1; |
| | 999 | + |
| | 1000 | + /* common name */ |
| | 1001 | + if (tag[0] == 'C' and tag[1] == 'N') { |
| | 1002 | + CN = begin; |
| | 1003 | + CN_len = len; |
| | 1004 | + |
| | 1005 | + /* organization */ |
| | 1006 | + } else if (tag[0] == 'O' and tag[1] == '\0') { |
| | 1007 | + O = begin; |
| | 1008 | + O_len = len; |
| | 1009 | + |
| | 1010 | + /* country */ |
| | 1011 | + } else if (tag[0] == 'C' and tag[1] == '\0') { |
| | 1012 | + C = begin; |
| | 1013 | + C_len = len; |
| | 1014 | + |
| | 1015 | + /* organisation unit */ |
| | 1016 | + } else if (tag[0] == 'O' and tag[1] == 'U') { |
| | 1017 | + OU = begin; |
| | 1018 | + OU_len = len; |
| | 1019 | + |
| | 1020 | + /* state */ |
| | 1021 | + } else if (tag[0] == 'S' and tag[1] == 'T') { |
| | 1022 | + ST = begin; |
| | 1023 | + ST_len = len; |
| | 1024 | + |
| | 1025 | + /* locality */ |
| | 1026 | + } else if (tag[0] == 'L' and tag[1] == '\0') { |
| | 1027 | + L = begin; |
| | 1028 | + L_len = len; |
| | 1029 | + |
| | 1030 | + /* email */ |
| | 1031 | + } else if (tag[0] == 'R' and tag[1] == '\0') { |
| | 1032 | + R = begin; |
| | 1033 | + R_len = len; |
| | 1034 | + } |
| | 1035 | + |
| | 1036 | + /* set tag poiner to begin */ |
| | 1037 | + tag_sp = tag; |
| | 1038 | + |
| | 1039 | + /* is at end? */ |
| | 1040 | + if (*sp == '\0' or *(sp +1) == '\0') |
| | 1041 | + break; |
| | 1042 | + } else { |
| | 1043 | + ++len; |
| | 1044 | + } |
| | 1045 | + } |
| | 1046 | + |
| | 1047 | + /* make saver */ |
| | 1048 | + if (*sp == '\0') |
| | 1049 | + break; |
| | 1050 | + } /* end for */ |
| | 1051 | + |
| | 1052 | + /* country */ |
| | 1053 | + if (C != NULL) { |
| | 1054 | + oid[2] = X520_COUNTRY; |
| | 1055 | + if ((ret = x509write_add_name(node, oid, 3, C, C_len, |
| | 1056 | + ASN1_PRINTABLE_STRING)) != 0) |
| | 1057 | + return ret; |
| | 1058 | + } |
| | 1059 | + |
| | 1060 | + /* state */ |
| | 1061 | + if (ST != NULL) { |
| | 1062 | + oid[2] = X520_STATE; |
| | 1063 | + if ((ret = x509write_add_name(node, oid, 3, ST, ST_len, |
| | 1064 | + ASN1_PRINTABLE_STRING)) != 0) |
| | 1065 | + return ret; |
| | 1066 | + } |
| | 1067 | + |
| | 1068 | + /* locality */ |
| | 1069 | + if (L != NULL) { |
| | 1070 | + oid[2] = X520_LOCALITY; |
| | 1071 | + if ((ret = x509write_add_name(node, oid, 3, L, L_len, |
| | 1072 | + ASN1_PRINTABLE_STRING)) != 0) |
| | 1073 | + return ret; |
| | 1074 | + } |
| | 1075 | + |
| | 1076 | + /* organization */ |
| | 1077 | + if (O != NULL) { |
| | 1078 | + oid[2] = X520_ORGANIZATION; |
| | 1079 | + if ((ret = x509write_add_name(node, oid, 3, O, O_len, |
| | 1080 | + ASN1_PRINTABLE_STRING)) != 0) |
| | 1081 | + return ret; |
| | 1082 | + } |
| | 1083 | + |
| | 1084 | + /* organisation unit */ |
| | 1085 | + if (OU != NULL) { |
| | 1086 | + oid[2] = X520_ORG_UNIT; |
| | 1087 | + if ((ret = x509write_add_name(node, oid, 3, OU, OU_len, |
| | 1088 | + ASN1_PRINTABLE_STRING)) != 0) |
| | 1089 | + return ret; |
| | 1090 | + } |
| | 1091 | + |
| | 1092 | + /* common name */ |
| | 1093 | + if (CN != NULL) { |
| | 1094 | + oid[2] = X520_COMMON_NAME; |
| | 1095 | + if ((ret = x509write_add_name(node, oid, 3, CN, CN_len, |
| | 1096 | + ASN1_PRINTABLE_STRING)) != 0) |
| | 1097 | + return ret; |
| | 1098 | + } |
| | 1099 | + |
| | 1100 | + /* email */ |
| | 1101 | + if (R != NULL) { |
| | 1102 | + if ((ret = x509write_add_name(node, (unsigned char*)OID_PKCS9_EMAIL, |
| | 1103 | + 9, R, R_len, ASN1_IA5_STRING)) != 0) |
| | 1104 | + return ret; |
| | 1105 | + } |
| | 1106 | + |
| | 1107 | + if ((asn1_append_tag(node, ASN1_CONSTRUCTED | ASN1_SEQUENCE)) != 0) |
| | 1108 | + return ret; |
| | 1109 | + |
| | 1110 | + return 0; |
| | 1111 | +} |
| | 1112 | + |
| | 1113 | +/* |
| | 1114 | + * Copy raw data from orginal ca to node |
| | 1115 | + */ |
| | 1116 | +static int x509write_copy_from_raw(x509_node *node, x509_buf *raw) |
| | 1117 | +{ |
| | 1118 | + if (x509write_realloc_node(node, raw->len) != 0) |
| | 1119 | + return 1; |
| | 1120 | + |
| | 1121 | + memcpy(node->p, raw->p, (size_t)raw->len); |
| | 1122 | + if ((node->p += raw->len -1) != node->end) |
| | 1123 | + return POLARSSL_ERR_X509_POINT_ERROR; |
| | 1124 | + |
| | 1125 | + return 0; |
| | 1126 | +} |
| | 1127 | + |
| | 1128 | +/* |
| | 1129 | + * Add the issuer |
| | 1130 | + */ |
| | 1131 | + |
| | 1132 | +int x509write_add_issuer(x509_raw *crt, unsigned char *issuer) |
| | 1133 | +{ |
| | 1134 | + return x509write_parse_names(&crt->issuer, issuer); |
| | 1135 | +} |
| | 1136 | + |
| | 1137 | +/* |
| | 1138 | + * Add the subject |
| | 1139 | + */ |
| | 1140 | +int x509write_add_subject(x509_raw *crt, unsigned char *subject) |
| | 1141 | +{ |
| | 1142 | + return x509write_parse_names(&crt->subject, subject); |
| | 1143 | +} |
| | 1144 | + |
| | 1145 | +/* |
| | 1146 | + * Copy issuer line from another cert to issuer |
| | 1147 | + */ |
| | 1148 | +int x509write_copy_issuer(x509_raw *crt, x509_cert *from_crt) |
| | 1149 | +{ |
| | 1150 | + return x509write_copy_from_raw(&crt->issuer, &from_crt->issuer_raw); |
| | 1151 | +} |
| | 1152 | + |
| | 1153 | +/* |
| | 1154 | + * Copy subject line from another cert |
| | 1155 | + */ |
| | 1156 | +int x509write_copy_subject(x509_raw *crt, x509_cert *from_crt) |
| | 1157 | +{ |
| | 1158 | + return x509write_copy_from_raw(&crt->subject, &from_crt->subject_raw); |
| | 1159 | +} |
| | 1160 | + |
| | 1161 | +/* |
| | 1162 | + * Copy subject line form antoher cert into issuer |
| | 1163 | + */ |
| | 1164 | +int x509write_copy_issuer_form_subject(x509_raw *crt, |
| | 1165 | + x509_cert *from_crt) |
| | 1166 | +{ |
| | 1167 | + return x509write_copy_from_raw(&crt->issuer, &from_crt->subject_raw); |
| | 1168 | +} |
| | 1169 | + |
| | 1170 | +/* |
| | 1171 | + * Copy issuer line from another cert into subject |
| | 1172 | + */ |
| | 1173 | +int x509write_copy_subject_from_issuer(x509_raw *crt, |
| | 1174 | + x509_cert * from_crt) |
| | 1175 | +{ |
| | 1176 | + return x509write_copy_from_raw(&crt->subject, &from_crt->issuer_raw); |
| | 1177 | +} |
| | 1178 | + |
| | 1179 | +/* |
| | 1180 | + * Validity ::= SEQUENCE { |
| | 1181 | + * notBefore Time, |
| | 1182 | + * notAfter Time } |
| | 1183 | + * |
| | 1184 | + * Time ::= CHOICE { |
| | 1185 | + * utcTime UTCTime, |
| | 1186 | + * generalTime GeneralizedTime } |
| | 1187 | + */ |
| | 1188 | +/* TODO: No handle GeneralizedTime! */ |
| | 1189 | +int x509write_add_validity(x509_raw *chain, unsigned char *befor, |
| | 1190 | + unsigned char *after) |
| | 1191 | +{ |
| | 1192 | + int ret; |
| | 1193 | + |
| | 1194 | + x509_node *node = &chain->validity; |
| | 1195 | + |
| | 1196 | + /* notBefore */ |
| | 1197 | + if ((ret = asn1_add_date_utc(befor, node)) != 0) |
| | 1198 | + return ret; |
| | 1199 | + |
| | 1200 | + /* notAfter */ |
| | 1201 | + if ((ret = asn1_add_date_utc(after, node)) != 0) |
| | 1202 | + return ret; |
| | 1203 | + |
| | 1204 | + if ((ret = asn1_append_tag(node, ASN1_CONSTRUCTED | ASN1_SEQUENCE)) != 0) |
| | 1205 | + return ret; |
| | 1206 | + |
| | 1207 | + return 0; |
| | 1208 | +} |
| | 1209 | + |
| | 1210 | +/* |
| | 1211 | + * make hash from tbs and sign that with private key |
| | 1212 | + */ |
| | 1213 | +static int x509write_make_sign(x509_raw *chain, rsa_context *privkey) |
| | 1214 | +{ |
| | 1215 | + int ret; |
| | 1216 | + unsigned char hash[20], *sign; |
| | 1217 | + size_t sign_len = (size_t) mpi_size(&privkey->N); |
| | 1218 | + |
| | 1219 | + /* make hash */ |
| | 1220 | + sha1(chain->tbs.data, chain->tbs.len, hash); |
| | 1221 | + |
| | 1222 | + /* create sign */ |
| | 1223 | + sign = (unsigned char *) malloc(sign_len); |
| | 1224 | + if (sign == NULL) |
| | 1225 | + return 1; |
| | 1226 | + |
| | 1227 | + if ((ret = rsa_pkcs1_sign(privkey, RSA_PRIVATE, SIG_RSA_SHA1, 20, hash, |
| | 1228 | + sign)) != 0) |
| | 1229 | + return ret; |
| | 1230 | + |
| | 1231 | + if ((ret = asn1_add_obj(sign, sign_len, ASN1_BIT_STRING, |
| | 1232 | + &chain->sign)) != 0) |
| | 1233 | + return ret; |
| | 1234 | + |
| | 1235 | + /* |
| | 1236 | + * AlgorithmIdentifier ::= SEQUENCE { |
| | 1237 | + * algorithm OBJECT IDENTIFIER, |
| | 1238 | + * parameters ANY DEFINED BY algorithm OPTIONAL } |
| | 1239 | + */ |
| | 1240 | + return asn1_add_oid(&chain->signalg, (unsigned char*)OID_PKCS1_RSA_SHA, 9, |
| | 1241 | + ASN1_CONSTRUCTED | ASN1_SEQUENCE, ASN1_NULL, |
| | 1242 | + (unsigned char*)"", 0); |
| | 1243 | +} |
| | 1244 | + |
| | 1245 | +/* |
| | 1246 | + * Create a self signed certificate |
| | 1247 | + */ |
| | 1248 | +int x509write_create_sign(x509_raw *chain, rsa_context *privkey) |
| | 1249 | +{ |
| | 1250 | + int ret, serial; |
| | 1251 | + |
| | 1252 | + /* |
| | 1253 | + * Version ::= INTEGER { v1(0), v2(1), v3(2) } |
| | 1254 | + */ |
| | 1255 | + if ((ret = asn1_add_int(2, &chain->version)) != 0) |
| | 1256 | + return ret; |
| | 1257 | + |
| | 1258 | + if ((ret = asn1_append_tag(&chain->version, ASN1_CONTEXT_SPECIFIC | |
| | 1259 | + ASN1_CONSTRUCTED)) != 0) |
| | 1260 | + return ret; |
| | 1261 | + |
| | 1262 | + |
| | 1263 | + /* |
| | 1264 | + * CertificateSerialNumber ::= INTEGER |
| | 1265 | + */ |
| | 1266 | + srand((unsigned int) time(NULL)); |
| | 1267 | + serial = rand(); |
| | 1268 | + if ((ret = asn1_add_int(serial, &chain->serial)) != 0) |
| | 1269 | + return ret; |
| | 1270 | + |
| | 1271 | + /* |
| | 1272 | + * AlgorithmIdentifier ::= SEQUENCE { |
| | 1273 | + * algorithm OBJECT IDENTIFIER, |
| | 1274 | + * parameters ANY DEFINED BY algorithm OPTIONAL } |
| | 1275 | + */ |
| | 1276 | + if ((ret = asn1_add_oid(&chain->tbs_signalg, |
| | 1277 | + (unsigned char*)OID_PKCS1_RSA_SHA, 9, ASN1_CONSTRUCTED | |
| | 1278 | + ASN1_SEQUENCE, ASN1_NULL, (unsigned char*)"", 0)) != 0) |
| | 1279 | + return ret; |
| | 1280 | + |
| | 1281 | + /* |
| | 1282 | + * Create the tbs |
| | 1283 | + */ |
| | 1284 | + if ((ret = asn1_append_nodes(&chain->tbs, ASN1_CONSTRUCTED | |
| | 1285 | + ASN1_SEQUENCE, 7, &chain->version, &chain->serial, |
| | 1286 | + &chain->tbs_signalg, &chain->issuer, &chain->validity, |
| | 1287 | + &chain->subject, &chain->subpubkey)) != 0) |
| | 1288 | + return ret; |
| | 1289 | + |
| | 1290 | + /* make signing */ |
| | 1291 | + if ((ret = x509write_make_sign(chain, privkey)) != 0) |
| | 1292 | + return ret; |
| | 1293 | + |
| | 1294 | + /* finishing */ |
| | 1295 | + if ((ret = asn1_append_nodes(&chain->raw, ASN1_CONSTRUCTED | |
| | 1296 | + ASN1_SEQUENCE, 3, &chain->tbs, &chain->signalg, |
| | 1297 | + &chain->sign)) != 0) |
| | 1298 | + return ret; |
| | 1299 | + |
| | 1300 | + return 0; |
| | 1301 | +} |
| | 1302 | + |
| | 1303 | +int x509write_create_selfsign(x509_raw *chain, rsa_context *privkey) |
| | 1304 | +{ |
| | 1305 | + /* |
| | 1306 | + * On self signed certificate are subject and issuer the same |
| | 1307 | + */ |
| | 1308 | + x509write_free_node(&chain->issuer); |
| | 1309 | + chain->issuer = chain->subject; |
| | 1310 | + return x509write_create_sign(chain, privkey); |
| | 1311 | +} |
| | 1312 | + |
| | 1313 | +/* |
| | 1314 | + * CertificationRequestInfo ::= SEQUENCE { |
| | 1315 | + * version Version, |
| | 1316 | + * subject Name, |
| | 1317 | + * subjectPublicKeyInfo SubjectPublicKeyInfo, |
| | 1318 | + * attributes [0] IMPLICIT Attributes } |
| | 1319 | + * |
| | 1320 | + * CertificationRequest ::= SEQUENCE { |
| | 1321 | + * certificationRequestInfo CertificationRequestInfo, |
| | 1322 | + * signatureAlgorithm SignatureAlgorithmIdentifier, |
| | 1323 | + * signature Signature } |
| | 1324 | + * |
| | 1325 | + * It use chain.serail for attributes! |
| | 1326 | + * |
| | 1327 | + */ |
| | 1328 | +int x509write_create_csr(x509_raw *chain, rsa_context *privkey) |
| | 1329 | +{ |
| | 1330 | + int ret; |
| | 1331 | + |
| | 1332 | + /* version ::= INTEGER */ |
| | 1333 | + if ((ret = asn1_add_int(0, &chain->version)) != 0) |
| | 1334 | + return ret; |
| | 1335 | + |
| | 1336 | + /* write attributes */ |
| | 1337 | + if ((ret = asn1_add_obj((unsigned char*)"", 0, ASN1_CONTEXT_SPECIFIC | |
| | 1338 | + ASN1_CONSTRUCTED, &chain->serial)) != 0) |
| | 1339 | + return ret; |
| | 1340 | + |
| | 1341 | + /* create CertificationRequestInfo */ |
| | 1342 | + if ((ret = asn1_append_nodes(&chain->tbs, ASN1_CONSTRUCTED | |
| | 1343 | + ASN1_SEQUENCE, 4, &chain->version, &chain->subject, |
| | 1344 | + &chain->subpubkey, &chain->serial)) != 0) |
| | 1345 | + return ret; |
| | 1346 | + |
| | 1347 | + /* make signing */ |
| | 1348 | + if ((ret = x509write_make_sign(chain, privkey)) != 0) |
| | 1349 | + return ret; |
| | 1350 | + |
| | 1351 | + /* finish */ |
| | 1352 | + if ((ret = asn1_append_nodes(&chain->raw, ASN1_CONSTRUCTED | ASN1_SEQUENCE, |
| | 1353 | + 3, &chain->tbs, &chain->signalg, &chain->sign)) != 0) |
| | 1354 | + return ret; |
| | 1355 | + |
| | 1356 | + return ret; |
| | 1357 | +} |
| | 1358 | + |
| | 1359 | +/* |
| | 1360 | + * Free memory |
| | 1361 | + */ |
| | 1362 | +void x509write_free_raw(x509_raw *chain) |
| | 1363 | +{ |
| | 1364 | + x509write_free_node(&chain->raw); |
| | 1365 | + x509write_free_node(&chain->tbs); |
| | 1366 | + x509write_free_node(&chain->version); |
| | 1367 | + x509write_free_node(&chain->serial); |
| | 1368 | + x509write_free_node(&chain->tbs_signalg); |
| | 1369 | + x509write_free_node(&chain->issuer); |
| | 1370 | + x509write_free_node(&chain->validity); |
| | 1371 | + if (chain->subject.data != chain->issuer.data) |
| | 1372 | + x509write_free_node(&chain->subject); |
| | 1373 | + x509write_free_node(&chain->subpubkey); |
| | 1374 | + x509write_free_node(&chain->signalg); |
| | 1375 | + x509write_free_node(&chain->sign); |
| | 1376 | +} |
| | 1377 | + |
| | 1378 | +void x509write_init_raw(x509_raw *chain) |
| | 1379 | +{ |
| | 1380 | + memset((void *) chain, 0, sizeof(x509_raw)); |
| | 1381 | +} |