1289177Speter/* 2289177Speter * X.509 certificate and private key decoding 3289177Speter * 4289177Speter * Based on XySSL: Copyright (C) 2006-2008 Christophe Devine 5289177Speter * 6289177Speter * Copyright (C) 2009 Paul Bakker <polarssl_maintainer at polarssl dot org> 7289177Speter * 8289177Speter * All rights reserved. 9289177Speter * 10289177Speter * Redistribution and use in source and binary forms, with or without 11289177Speter * modification, are permitted provided that the following conditions 12289177Speter * are met: 13289177Speter * 14289177Speter * * Redistributions of source code must retain the above copyright 15289177Speter * notice, this list of conditions and the following disclaimer. 16289177Speter * * Redistributions in binary form must reproduce the above copyright 17289177Speter * notice, this list of conditions and the following disclaimer in the 18289177Speter * documentation and/or other materials provided with the distribution. 19289177Speter * * Neither the names of PolarSSL or XySSL nor the names of its contributors 20289177Speter * may be used to endorse or promote products derived from this software 21289177Speter * without specific prior written permission. 22289177Speter * 23289177Speter * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24289177Speter * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25289177Speter * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26289177Speter * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27289177Speter * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28289177Speter * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29289177Speter * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30289177Speter * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31289177Speter * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32289177Speter * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33289177Speter * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34289177Speter */ 35289177Speter/* 36289177Speter * The ITU-T X.509 standard defines a certificate format for PKI. 37289177Speter * 38289177Speter * http://www.ietf.org/rfc/rfc5280.txt 39289177Speter * http://www.ietf.org/rfc/rfc3279.txt 40289177Speter * http://www.ietf.org/rfc/rfc6818.txt 41289177Speter * 42289177Speter * ftp://ftp.rsasecurity.com/pub/pkcs/ascii/pkcs-1v2.asc 43289177Speter * 44289177Speter * http://www.itu.int/ITU-T/studygroups/com17/languages/X.680-0207.pdf 45289177Speter * http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf 46289177Speter */ 47289177Speter 48289177Speter#include <apr_pools.h> 49289177Speter#include <apr_tables.h> 50289177Speter#include "svn_hash.h" 51289177Speter#include "svn_string.h" 52289177Speter#include "svn_time.h" 53289177Speter#include "svn_checksum.h" 54289177Speter#include "svn_utf.h" 55289177Speter#include "svn_ctype.h" 56289177Speter#include "private/svn_utf_private.h" 57289177Speter#include "private/svn_string_private.h" 58289177Speter 59289177Speter#include "x509.h" 60289177Speter 61289177Speter#include <string.h> 62289177Speter#include <stdio.h> 63289177Speter 64289177Speter/* 65289177Speter * ASN.1 DER decoding routines 66289177Speter */ 67289177Speterstatic svn_error_t * 68289177Speterasn1_get_len(const unsigned char **p, const unsigned char *end, 69289177Speter ptrdiff_t *len) 70289177Speter{ 71289177Speter if ((end - *p) < 1) 72289177Speter return svn_error_create(SVN_ERR_ASN1_OUT_OF_DATA, NULL, NULL); 73289177Speter 74289177Speter if ((**p & 0x80) == 0) 75289177Speter *len = *(*p)++; 76289177Speter else 77289177Speter switch (**p & 0x7F) 78289177Speter { 79289177Speter case 1: 80289177Speter if ((end - *p) < 2) 81289177Speter return svn_error_create(SVN_ERR_ASN1_OUT_OF_DATA, NULL, NULL); 82289177Speter 83289177Speter *len = (*p)[1]; 84289177Speter (*p) += 2; 85289177Speter break; 86289177Speter 87289177Speter case 2: 88289177Speter if ((end - *p) < 3) 89289177Speter return svn_error_create(SVN_ERR_ASN1_OUT_OF_DATA, NULL, NULL); 90289177Speter 91289177Speter *len = ((*p)[1] << 8) | (*p)[2]; 92289177Speter (*p) += 3; 93289177Speter break; 94289177Speter 95289177Speter default: 96289177Speter return svn_error_create(SVN_ERR_ASN1_INVALID_LENGTH, NULL, NULL); 97289177Speter break; 98289177Speter } 99289177Speter 100289177Speter if (*len > (end - *p)) 101289177Speter return svn_error_create(SVN_ERR_ASN1_OUT_OF_DATA, NULL, NULL); 102289177Speter 103289177Speter return SVN_NO_ERROR; 104289177Speter} 105289177Speter 106289177Speterstatic svn_error_t * 107289177Speterasn1_get_tag(const unsigned char **p, 108289177Speter const unsigned char *end, ptrdiff_t *len, int tag) 109289177Speter{ 110289177Speter if ((end - *p) < 1) 111289177Speter return svn_error_create(SVN_ERR_ASN1_OUT_OF_DATA, NULL, NULL); 112289177Speter 113289177Speter if (**p != tag) 114289177Speter return svn_error_create(SVN_ERR_ASN1_UNEXPECTED_TAG, NULL, NULL); 115289177Speter 116289177Speter (*p)++; 117289177Speter 118289177Speter return svn_error_trace(asn1_get_len(p, end, len)); 119289177Speter} 120289177Speter 121289177Speterstatic svn_error_t * 122289177Speterasn1_get_int(const unsigned char **p, const unsigned char *end, int *val) 123289177Speter{ 124289177Speter ptrdiff_t len; 125289177Speter 126289177Speter SVN_ERR(asn1_get_tag(p, end, &len, ASN1_INTEGER)); 127289177Speter 128289177Speter /* Reject bit patterns that would overflow the output and those that 129289177Speter represent negative values. */ 130289177Speter if (len > (int)sizeof(int) || (**p & 0x80) != 0) 131289177Speter return svn_error_create(SVN_ERR_ASN1_INVALID_LENGTH, NULL, NULL); 132289177Speter 133289177Speter *val = 0; 134289177Speter 135289177Speter while (len-- > 0) { 136289177Speter /* This would be undefined for bit-patterns of negative values. */ 137289177Speter *val = (*val << 8) | **p; 138289177Speter (*p)++; 139289177Speter } 140289177Speter 141289177Speter return SVN_NO_ERROR; 142289177Speter} 143289177Speter 144289177Speterstatic svn_boolean_t 145289177Speterequal(const void *left, apr_size_t left_len, 146289177Speter const void *right, apr_size_t right_len) 147289177Speter{ 148289177Speter if (left_len != right_len) 149289177Speter return FALSE; 150289177Speter 151289177Speter return memcmp(left, right, right_len) == 0; 152289177Speter} 153289177Speter 154289177Speterstatic svn_boolean_t 155289177Speteroids_equal(x509_buf *left, x509_buf *right) 156289177Speter{ 157289177Speter return equal(left->p, left->len, 158289177Speter right->p, right->len); 159289177Speter} 160289177Speter 161289177Speter/* 162289177Speter * Version ::= INTEGER { v1(0), v2(1), v3(2) } 163289177Speter */ 164289177Speterstatic svn_error_t * 165289177Speterx509_get_version(const unsigned char **p, const unsigned char *end, int *ver) 166289177Speter{ 167289177Speter svn_error_t *err; 168289177Speter ptrdiff_t len; 169289177Speter 170289177Speter /* 171289177Speter * As defined in the Basic Certificate fields: 172289177Speter * version [0] EXPLICIT Version DEFAULT v1, 173289177Speter * the version is the context specific tag 0. 174289177Speter */ 175289177Speter err = asn1_get_tag(p, end, &len, 176289177Speter ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 0); 177289177Speter if (err) 178289177Speter { 179289177Speter if (err->apr_err == SVN_ERR_ASN1_UNEXPECTED_TAG) 180289177Speter { 181289177Speter svn_error_clear(err); 182289177Speter *ver = 0; 183289177Speter return SVN_NO_ERROR; 184289177Speter } 185289177Speter 186289177Speter return svn_error_trace(err); 187289177Speter } 188289177Speter 189289177Speter end = *p + len; 190289177Speter 191289177Speter err = asn1_get_int(p, end, ver); 192289177Speter if (err) 193289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_VERSION, err, NULL); 194289177Speter 195289177Speter if (*p != end) 196289177Speter { 197289177Speter err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL); 198289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_VERSION, err, NULL); 199289177Speter } 200289177Speter 201289177Speter return SVN_NO_ERROR; 202289177Speter} 203289177Speter 204289177Speter/* 205289177Speter * CertificateSerialNumber ::= INTEGER 206289177Speter */ 207289177Speterstatic svn_error_t * 208289177Speterx509_get_serial(const unsigned char **p, 209289177Speter const unsigned char *end, x509_buf * serial) 210289177Speter{ 211289177Speter svn_error_t *err; 212289177Speter 213289177Speter if ((end - *p) < 1) 214289177Speter { 215289177Speter err = svn_error_create(SVN_ERR_ASN1_OUT_OF_DATA, NULL, NULL); 216289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_SERIAL, err, NULL); 217289177Speter } 218289177Speter 219289177Speter if (**p != (ASN1_CONTEXT_SPECIFIC | ASN1_PRIMITIVE | 2) && 220289177Speter **p != ASN1_INTEGER) 221289177Speter { 222289177Speter err = svn_error_create(SVN_ERR_ASN1_UNEXPECTED_TAG, NULL, NULL); 223289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_SERIAL, err, NULL); 224289177Speter } 225289177Speter 226289177Speter serial->tag = *(*p)++; 227289177Speter 228289177Speter err = asn1_get_len(p, end, &serial->len); 229289177Speter if (err) 230289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_SERIAL, err, NULL); 231289177Speter 232289177Speter serial->p = *p; 233289177Speter *p += serial->len; 234289177Speter 235289177Speter return SVN_NO_ERROR; 236289177Speter} 237289177Speter 238289177Speter/* 239289177Speter * AlgorithmIdentifier ::= SEQUENCE { 240289177Speter * algorithm OBJECT IDENTIFIER, 241289177Speter * parameters ANY DEFINED BY algorithm OPTIONAL } 242289177Speter */ 243289177Speterstatic svn_error_t * 244289177Speterx509_get_alg(const unsigned char **p, const unsigned char *end, x509_buf * alg) 245289177Speter{ 246289177Speter svn_error_t *err; 247289177Speter ptrdiff_t len; 248289177Speter 249289177Speter err = asn1_get_tag(p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE); 250289177Speter if (err) 251289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_ALG, err, NULL); 252289177Speter 253289177Speter end = *p + len; 254289177Speter alg->tag = **p; 255289177Speter 256289177Speter err = asn1_get_tag(p, end, &alg->len, ASN1_OID); 257289177Speter if (err) 258289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_ALG, err, NULL); 259289177Speter 260289177Speter alg->p = *p; 261289177Speter *p += alg->len; 262289177Speter 263289177Speter if (*p == end) 264289177Speter return SVN_NO_ERROR; 265289177Speter 266289177Speter /* 267289177Speter * assume the algorithm parameters must be NULL 268289177Speter */ 269289177Speter err = asn1_get_tag(p, end, &len, ASN1_NULL); 270289177Speter if (err) 271289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_ALG, err, NULL); 272289177Speter 273289177Speter if (*p != end) 274289177Speter { 275289177Speter err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL); 276289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_ALG, err, NULL); 277289177Speter } 278289177Speter 279289177Speter return SVN_NO_ERROR; 280289177Speter} 281289177Speter 282289177Speter/* 283289177Speter * AttributeTypeAndValue ::= SEQUENCE { 284289177Speter * type AttributeType, 285289177Speter * value AttributeValue } 286289177Speter * 287289177Speter * AttributeType ::= OBJECT IDENTIFIER 288289177Speter * 289289177Speter * AttributeValue ::= ANY DEFINED BY AttributeType 290289177Speter */ 291289177Speterstatic svn_error_t * 292289177Speterx509_get_attribute(const unsigned char **p, const unsigned char *end, 293289177Speter x509_name *cur, apr_pool_t *result_pool) 294289177Speter{ 295289177Speter svn_error_t *err; 296289177Speter ptrdiff_t len; 297289177Speter x509_buf *oid; 298289177Speter x509_buf *val; 299289177Speter 300289177Speter err = asn1_get_tag(p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE); 301289177Speter if (err) 302289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_NAME, err, NULL); 303289177Speter 304289177Speter end = *p + len; 305289177Speter 306289177Speter oid = &cur->oid; 307289177Speter 308289177Speter err = asn1_get_tag(p, end, &oid->len, ASN1_OID); 309289177Speter if (err) 310289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_NAME, err, NULL); 311289177Speter 312289177Speter oid->tag = ASN1_OID; 313289177Speter oid->p = *p; 314289177Speter *p += oid->len; 315289177Speter 316289177Speter if ((end - *p) < 1) 317289177Speter { 318289177Speter err = svn_error_create(SVN_ERR_ASN1_OUT_OF_DATA, NULL, NULL); 319289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_NAME, err, NULL); 320289177Speter } 321289177Speter 322289177Speter if (**p != ASN1_BMP_STRING && **p != ASN1_UTF8_STRING && 323289177Speter **p != ASN1_T61_STRING && **p != ASN1_PRINTABLE_STRING && 324289177Speter **p != ASN1_IA5_STRING && **p != ASN1_UNIVERSAL_STRING) 325289177Speter { 326289177Speter err = svn_error_create(SVN_ERR_ASN1_UNEXPECTED_TAG, NULL, NULL); 327289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_NAME, err, NULL); 328289177Speter } 329289177Speter 330289177Speter val = &cur->val; 331289177Speter val->tag = *(*p)++; 332289177Speter 333289177Speter err = asn1_get_len(p, end, &val->len); 334289177Speter if (err) 335289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_NAME, err, NULL); 336289177Speter 337289177Speter val->p = *p; 338289177Speter *p += val->len; 339289177Speter 340289177Speter cur->next = NULL; 341289177Speter 342289177Speter if (*p != end) 343289177Speter { 344289177Speter err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL); 345289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_NAME, err, NULL); 346289177Speter } 347289177Speter 348289177Speter return SVN_NO_ERROR; 349289177Speter} 350289177Speter 351289177Speter/* 352289177Speter * RelativeDistinguishedName ::= 353289177Speter * SET SIZE (1..MAX) OF AttributeTypeAndValue 354289177Speter */ 355289177Speterstatic svn_error_t * 356289177Speterx509_get_name(const unsigned char **p, const unsigned char *name_end, 357289177Speter x509_name *name, apr_pool_t *result_pool) 358289177Speter{ 359289177Speter svn_error_t *err; 360289177Speter ptrdiff_t len; 361289177Speter const unsigned char *set_end; 362289177Speter x509_name *cur = NULL; 363289177Speter 364289177Speter err = asn1_get_tag(p, name_end, &len, ASN1_CONSTRUCTED | ASN1_SET); 365289177Speter if (err) 366289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_NAME, err, NULL); 367289177Speter 368289177Speter set_end = *p + len; 369289177Speter 370289177Speter /* 371289177Speter * iterate until the end of the SET is reached 372289177Speter */ 373289177Speter while (*p < set_end) 374289177Speter { 375289177Speter if (!cur) 376289177Speter { 377289177Speter cur = name; 378289177Speter } 379289177Speter else 380289177Speter { 381289177Speter cur->next = apr_palloc(result_pool, sizeof(x509_name)); 382289177Speter cur = cur->next; 383289177Speter } 384289177Speter SVN_ERR(x509_get_attribute(p, set_end, cur, result_pool)); 385289177Speter } 386289177Speter 387289177Speter /* 388289177Speter * recurse until end of SEQUENCE (name) is reached 389289177Speter */ 390289177Speter if (*p == name_end) 391289177Speter return SVN_NO_ERROR; 392289177Speter 393289177Speter cur->next = apr_palloc(result_pool, sizeof(x509_name)); 394289177Speter 395289177Speter return svn_error_trace(x509_get_name(p, name_end, cur->next, result_pool)); 396289177Speter} 397289177Speter 398289177Speter/* Retrieve the date from the X.509 cert data between *P and END in either 399289177Speter * UTCTime or GeneralizedTime format (as defined in RFC 5280 s. 4.1.2.5.1 and 400289177Speter * 4.1.2.5.2 respectively) and place the result in WHEN using SCRATCH_POOL 401289177Speter * for temporary allocations. */ 402289177Speterstatic svn_error_t * 403289177Speterx509_get_date(apr_time_t *when, 404289177Speter const unsigned char **p, 405289177Speter const unsigned char *end, 406289177Speter apr_pool_t *scratch_pool) 407289177Speter{ 408289177Speter svn_error_t *err; 409289177Speter apr_status_t ret; 410289177Speter int tag; 411289177Speter ptrdiff_t len; 412289177Speter char *date; 413289177Speter apr_time_exp_t xt = { 0 }; 414289177Speter char tz; 415289177Speter 416289177Speter err = asn1_get_tag(p, end, &len, ASN1_UTC_TIME); 417289177Speter if (err && err->apr_err == SVN_ERR_ASN1_UNEXPECTED_TAG) 418289177Speter { 419289177Speter svn_error_clear(err); 420289177Speter err = asn1_get_tag(p, end, &len, ASN1_GENERALIZED_TIME); 421289177Speter tag = ASN1_GENERALIZED_TIME; 422289177Speter } 423289177Speter else 424289177Speter { 425289177Speter tag = ASN1_UTC_TIME; 426289177Speter } 427289177Speter if (err) 428289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_DATE, err, NULL); 429289177Speter 430289177Speter date = apr_pstrndup(scratch_pool, (const char *) *p, len); 431289177Speter switch (tag) 432289177Speter { 433289177Speter case ASN1_UTC_TIME: 434289177Speter if (sscanf(date, "%2d%2d%2d%2d%2d%2d%c", 435289177Speter &xt.tm_year, &xt.tm_mon, &xt.tm_mday, 436289177Speter &xt.tm_hour, &xt.tm_min, &xt.tm_sec, &tz) < 6) 437289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_DATE, NULL, NULL); 438289177Speter 439289177Speter /* UTCTime only provides a 2 digit year. X.509 specifies that years 440289177Speter * greater than or equal to 50 must be interpreted as 19YY and years 441289177Speter * less than 50 be interpreted as 20YY. This format is not used for 442289177Speter * years greater than 2049. apr_time_exp_t wants years as the number 443289177Speter * of years since 1900, so don't convert to 4 digits here. */ 444289177Speter xt.tm_year += 100 * (xt.tm_year < 50); 445289177Speter break; 446289177Speter 447289177Speter case ASN1_GENERALIZED_TIME: 448289177Speter if (sscanf(date, "%4d%2d%2d%2d%2d%2d%c", 449289177Speter &xt.tm_year, &xt.tm_mon, &xt.tm_mday, 450289177Speter &xt.tm_hour, &xt.tm_min, &xt.tm_sec, &tz) < 6) 451289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_DATE, NULL, NULL); 452289177Speter 453289177Speter /* GeneralizedTime has the full 4 digit year. But apr_time_exp_t 454289177Speter * wants years as the number of years since 1900. */ 455289177Speter xt.tm_year -= 1900; 456289177Speter break; 457289177Speter 458289177Speter default: 459289177Speter /* shouldn't ever get here because we should error out above in the 460289177Speter * asn1_get_tag() bits but doesn't hurt to be extra paranoid. */ 461289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_DATE, NULL, NULL); 462289177Speter break; 463289177Speter } 464289177Speter 465289177Speter /* check that the timezone is GMT 466289177Speter * ASN.1 allows for the timezone to be specified but X.509 says it must 467289177Speter * always be GMT. A little bit of extra paranoia here seems like a good 468289177Speter * idea. */ 469289177Speter if (tz != 'Z') 470289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_DATE, NULL, NULL); 471289177Speter 472289177Speter /* apr_time_exp_t expects months to be zero indexed, 0=Jan, 11=Dec. */ 473289177Speter xt.tm_mon -= 1; 474289177Speter 475289177Speter ret = apr_time_exp_gmt_get(when, &xt); 476289177Speter if (ret) 477289177Speter return svn_error_wrap_apr(ret, NULL); 478289177Speter 479289177Speter *p += len; 480289177Speter 481289177Speter return SVN_NO_ERROR; 482289177Speter} 483289177Speter 484289177Speter/* 485289177Speter * Validity ::= SEQUENCE { 486289177Speter * notBefore Time, 487289177Speter * notAfter Time } 488289177Speter * 489289177Speter * Time ::= CHOICE { 490289177Speter * utcTime UTCTime, 491289177Speter * generalTime GeneralizedTime } 492289177Speter */ 493289177Speterstatic svn_error_t * 494289177Speterx509_get_dates(apr_time_t *from, 495289177Speter apr_time_t *to, 496289177Speter const unsigned char **p, 497289177Speter const unsigned char *end, 498289177Speter apr_pool_t *scratch_pool) 499289177Speter{ 500289177Speter svn_error_t *err; 501289177Speter ptrdiff_t len; 502289177Speter 503289177Speter err = asn1_get_tag(p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE); 504289177Speter if (err) 505289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_DATE, err, NULL); 506289177Speter 507289177Speter end = *p + len; 508289177Speter 509289177Speter SVN_ERR(x509_get_date(from, p, end, scratch_pool)); 510289177Speter 511289177Speter SVN_ERR(x509_get_date(to, p, end, scratch_pool)); 512289177Speter 513289177Speter if (*p != end) 514289177Speter { 515289177Speter err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL); 516289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_DATE, err, NULL); 517289177Speter } 518289177Speter 519289177Speter return SVN_NO_ERROR; 520289177Speter} 521289177Speter 522289177Speterstatic svn_error_t * 523289177Speterx509_get_sig(const unsigned char **p, const unsigned char *end, x509_buf * sig) 524289177Speter{ 525289177Speter svn_error_t *err; 526289177Speter ptrdiff_t len; 527289177Speter 528289177Speter err = asn1_get_tag(p, end, &len, ASN1_BIT_STRING); 529289177Speter if (err) 530289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_SIGNATURE, err, NULL); 531289177Speter 532289177Speter sig->tag = ASN1_BIT_STRING; 533289177Speter 534289177Speter if (--len < 1 || *(*p)++ != 0) 535289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_SIGNATURE, NULL, NULL); 536289177Speter 537289177Speter sig->len = len; 538289177Speter sig->p = *p; 539289177Speter 540289177Speter *p += len; 541289177Speter 542289177Speter return SVN_NO_ERROR; 543289177Speter} 544289177Speter 545289177Speter/* 546289177Speter * X.509 v2/v3 unique identifier (not parsed) 547289177Speter */ 548289177Speterstatic svn_error_t * 549289177Speterx509_get_uid(const unsigned char **p, 550289177Speter const unsigned char *end, x509_buf * uid, int n) 551289177Speter{ 552289177Speter svn_error_t *err; 553289177Speter 554289177Speter if (*p == end) 555289177Speter return SVN_NO_ERROR; 556289177Speter 557289177Speter err = asn1_get_tag(p, end, &uid->len, 558289177Speter ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | n); 559289177Speter if (err) 560289177Speter { 561289177Speter if (err->apr_err == SVN_ERR_ASN1_UNEXPECTED_TAG) 562289177Speter { 563289177Speter svn_error_clear(err); 564289177Speter return SVN_NO_ERROR; 565289177Speter } 566289177Speter 567289177Speter return svn_error_trace(err); 568289177Speter } 569289177Speter 570289177Speter uid->tag = ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | n; 571289177Speter uid->p = *p; 572289177Speter *p += uid->len; 573289177Speter 574289177Speter return SVN_NO_ERROR; 575289177Speter} 576289177Speter 577289177Speter/* 578289177Speter * X.509 v3 extensions (not parsed) 579289177Speter */ 580289177Speterstatic svn_error_t * 581289177Speterx509_get_ext(apr_array_header_t *dnsnames, 582289177Speter const unsigned char **p, 583289177Speter const unsigned char *end) 584289177Speter{ 585289177Speter svn_error_t *err; 586289177Speter ptrdiff_t len; 587289177Speter 588289177Speter if (*p == end) 589289177Speter return SVN_NO_ERROR; 590289177Speter 591289177Speter err = asn1_get_tag(p, end, &len, 592289177Speter ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 3); 593289177Speter if (err) 594289177Speter { 595289177Speter /* If there aren't extensions that's ok they aren't required */ 596289177Speter if (err->apr_err == SVN_ERR_ASN1_UNEXPECTED_TAG) 597289177Speter { 598289177Speter svn_error_clear(err); 599289177Speter return SVN_NO_ERROR; 600289177Speter } 601289177Speter 602289177Speter return svn_error_trace(err); 603289177Speter } 604289177Speter 605289177Speter end = *p + len; 606289177Speter 607289177Speter SVN_ERR(asn1_get_tag(p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE)); 608289177Speter 609289177Speter if (end != *p + len) 610289177Speter { 611289177Speter err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL); 612289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_EXTENSIONS, err, NULL); 613289177Speter } 614289177Speter 615289177Speter while (*p < end) 616289177Speter { 617289177Speter ptrdiff_t ext_len; 618289177Speter const unsigned char *ext_start, *sna_end; 619289177Speter err = asn1_get_tag(p, end, &ext_len, ASN1_CONSTRUCTED | ASN1_SEQUENCE); 620289177Speter if (err) 621289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_EXTENSIONS, err, 622289177Speter NULL); 623289177Speter ext_start = *p; 624289177Speter 625289177Speter err = asn1_get_tag(p, end, &len, ASN1_OID); 626289177Speter if (err) 627289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_EXTENSIONS, err, 628289177Speter NULL); 629289177Speter 630289177Speter /* skip all extensions except SubjectAltName */ 631289177Speter if (!equal(*p, len, 632289177Speter OID_SUBJECT_ALT_NAME, sizeof(OID_SUBJECT_ALT_NAME) - 1)) 633289177Speter { 634289177Speter *p += ext_len - (*p - ext_start); 635289177Speter continue; 636289177Speter } 637289177Speter *p += len; 638289177Speter 639289177Speter err = asn1_get_tag(p, end, &len, ASN1_OCTET_STRING); 640289177Speter if (err) 641289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_EXTENSIONS, err, 642289177Speter NULL); 643289177Speter 644289177Speter /* SubjectAltName ::= GeneralNames 645289177Speter 646289177Speter GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName 647289177Speter 648289177Speter GeneralName ::= CHOICE { 649289177Speter other Name [0] OtherName, 650289177Speter rfc822Name [1] IA5String, 651289177Speter dNSName [2] IA5String, 652289177Speter x400Address [3] ORAddress, 653289177Speter directoryName [4] Name, 654289177Speter ediPartyName [5] EDIPartyName, 655289177Speter uniformResourceIdentifier [6] IA5String, 656289177Speter iPAddress [7] OCTET STRING, 657289177Speter registeredID [8] OBJECT IDENTIFIER } */ 658289177Speter sna_end = *p + len; 659289177Speter 660289177Speter err = asn1_get_tag(p, sna_end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE); 661289177Speter if (err) 662289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_EXTENSIONS, err, 663289177Speter NULL); 664289177Speter 665289177Speter if (sna_end != *p + len) 666289177Speter { 667289177Speter err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL); 668289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_EXTENSIONS, err, NULL); 669289177Speter } 670289177Speter 671289177Speter while (*p < sna_end) 672289177Speter { 673289177Speter err = asn1_get_tag(p, sna_end, &len, ASN1_CONTEXT_SPECIFIC | 674289177Speter ASN1_PRIMITIVE | 2); 675289177Speter if (err) 676289177Speter { 677289177Speter /* not not a dNSName */ 678289177Speter if (err->apr_err == SVN_ERR_ASN1_UNEXPECTED_TAG) 679289177Speter { 680289177Speter svn_error_clear(err); 681289177Speter /* need to skip the tag and then find the length to 682289177Speter * skip to ignore this SNA entry. */ 683289177Speter (*p)++; 684289177Speter SVN_ERR(asn1_get_len(p, sna_end, &len)); 685289177Speter *p += len; 686289177Speter continue; 687289177Speter } 688289177Speter 689289177Speter return svn_error_trace(err); 690289177Speter } 691289177Speter else 692289177Speter { 693289177Speter /* We found a dNSName entry */ 694289177Speter x509_buf *dnsname = apr_palloc(dnsnames->pool, 695289177Speter sizeof(x509_buf)); 696289177Speter dnsname->tag = ASN1_IA5_STRING; /* implicit based on dNSName */ 697289177Speter dnsname->len = len; 698289177Speter dnsname->p = *p; 699289177Speter APR_ARRAY_PUSH(dnsnames, x509_buf *) = dnsname; 700289177Speter } 701289177Speter 702289177Speter *p += len; 703289177Speter } 704289177Speter 705289177Speter } 706289177Speter 707289177Speter return SVN_NO_ERROR; 708289177Speter} 709289177Speter 710289177Speter/* Escape all non-ascii or control characters similar to 711289177Speter * svn_xml_fuzzy_escape() and svn_utf_cstring_from_utf8_fuzzy(). 712289177Speter * All of the encoding formats somewhat overlap with ascii (BMPString 713289177Speter * and UniversalString are actually always wider so you'll end up 714289177Speter * with a bunch of escaped nul bytes, but ideally we don't get here 715289177Speter * for those). The result is always a nul-terminated C string. */ 716289177Speterstatic const char * 717289177Speterfuzzy_escape(const svn_string_t *src, apr_pool_t *result_pool) 718289177Speter{ 719289177Speter const char *end = src->data + src->len; 720289177Speter const char *p = src->data, *q; 721289177Speter svn_stringbuf_t *outstr; 722289177Speter char escaped_char[6]; /* ? \ u u u \0 */ 723289177Speter 724289177Speter for (q = p; q < end; q++) 725289177Speter { 726289177Speter if (!svn_ctype_isascii(*q) || svn_ctype_iscntrl(*q)) 727289177Speter break; 728289177Speter } 729289177Speter 730289177Speter if (q == end) 731289177Speter return src->data; 732289177Speter 733289177Speter outstr = svn_stringbuf_create_empty(result_pool); 734289177Speter while (1) 735289177Speter { 736289177Speter q = p; 737289177Speter 738289177Speter /* Traverse till either unsafe character or eos. */ 739289177Speter while (q < end && svn_ctype_isascii(*q) && !svn_ctype_iscntrl(*q)) 740289177Speter q++; 741289177Speter 742289177Speter /* copy chunk before marker */ 743289177Speter svn_stringbuf_appendbytes(outstr, p, q - p); 744289177Speter 745289177Speter if (q == end) 746289177Speter break; 747289177Speter 748289177Speter apr_snprintf(escaped_char, sizeof(escaped_char), "?\\%03u", 749289177Speter (unsigned char) *q); 750289177Speter svn_stringbuf_appendcstr(outstr, escaped_char); 751289177Speter 752289177Speter p = q + 1; 753289177Speter } 754289177Speter 755289177Speter return outstr->data; 756289177Speter} 757289177Speter 758289177Speter/* Escape only NUL characters from a string that is presumed to 759289177Speter * be UTF-8 encoded and return a nul-terminated C string. */ 760289177Speterstatic const char * 761289177Speternul_escape(const svn_string_t *src, apr_pool_t *result_pool) 762289177Speter{ 763289177Speter const char *end = src->data + src->len; 764289177Speter const char *p = src->data, *q; 765289177Speter svn_stringbuf_t *outstr; 766289177Speter 767289177Speter for (q = p; q < end; q++) 768289177Speter { 769289177Speter if (*q == '\0') 770289177Speter break; 771289177Speter } 772289177Speter 773289177Speter if (q == end) 774289177Speter return src->data; 775289177Speter 776289177Speter outstr = svn_stringbuf_create_empty(result_pool); 777289177Speter while (1) 778289177Speter { 779289177Speter q = p; 780289177Speter 781289177Speter /* Traverse till either unsafe character or eos. */ 782289177Speter while (q < end && *q != '\0') 783289177Speter q++; 784289177Speter 785289177Speter /* copy chunk before marker */ 786289177Speter svn_stringbuf_appendbytes(outstr, p, q - p); 787289177Speter 788289177Speter if (q == end) 789289177Speter break; 790289177Speter 791289177Speter svn_stringbuf_appendcstr(outstr, "?\\000"); 792289177Speter 793289177Speter p = q + 1; 794289177Speter } 795289177Speter 796289177Speter return outstr->data; 797289177Speter} 798289177Speter 799289177Speter 800289177Speter/* Convert an ISO-8859-1 (Latin-1) string to UTF-8. 801289177Speter ISO-8859-1 is a strict subset of Unicode. */ 802289177Speterstatic svn_error_t * 803289177Speterlatin1_to_utf8(const svn_string_t **result, const svn_string_t *src, 804289177Speter apr_pool_t *result_pool) 805289177Speter{ 806289177Speter apr_int32_t *ucs4buf; 807289177Speter svn_membuf_t resultbuf; 808289177Speter apr_size_t length; 809289177Speter apr_size_t i; 810289177Speter svn_string_t *res; 811289177Speter 812289177Speter ucs4buf = apr_palloc(result_pool, src->len * sizeof(*ucs4buf)); 813289177Speter for (i = 0; i < src->len; ++i) 814289177Speter ucs4buf[i] = (unsigned char)(src->data[i]); 815289177Speter 816289177Speter svn_membuf__create(&resultbuf, 2 * src->len, result_pool); 817289177Speter SVN_ERR(svn_utf__encode_ucs4_string( 818289177Speter &resultbuf, ucs4buf, src->len, &length)); 819289177Speter 820289177Speter res = apr_palloc(result_pool, sizeof(*res)); 821289177Speter res->data = resultbuf.data; 822289177Speter res->len = length; 823289177Speter *result = res; 824289177Speter return SVN_NO_ERROR; 825289177Speter} 826289177Speter 827289177Speter/* Make a best effort to convert a X.509 name to a UTF-8 encoded 828289177Speter * string and return it. If we can't properly convert just do a 829289177Speter * fuzzy conversion so we have something to display. */ 830289177Speterstatic const char * 831289177Speterx509name_to_utf8_string(const x509_name *name, apr_pool_t *result_pool) 832289177Speter{ 833289177Speter const svn_string_t *src_string; 834289177Speter const svn_string_t *utf8_string; 835289177Speter svn_error_t *err; 836289177Speter 837289177Speter src_string = svn_string_ncreate((const char *)name->val.p, 838289177Speter name->val.len, 839289177Speter result_pool); 840289177Speter switch (name->val.tag) 841289177Speter { 842289177Speter case ASN1_UTF8_STRING: 843289177Speter if (svn_utf__is_valid(src_string->data, src_string->len)) 844289177Speter return nul_escape(src_string, result_pool); 845289177Speter else 846289177Speter /* not a valid UTF-8 string, who knows what it is, 847289177Speter * so run it through the fuzzy_escape code. */ 848289177Speter return fuzzy_escape(src_string, result_pool); 849289177Speter break; 850289177Speter 851289177Speter /* Both BMP and UNIVERSAL should always be in Big Endian (aka 852289177Speter * network byte order). But rumor has it that there are certs 853289177Speter * out there with other endianess and even Byte Order Marks. 854289177Speter * If we actually run into these, we might need to do something 855289177Speter * about it. */ 856289177Speter 857289177Speter case ASN1_BMP_STRING: 858289177Speter if (0 != src_string->len % sizeof(apr_uint16_t)) 859289177Speter return fuzzy_escape(src_string, result_pool); 860289177Speter err = svn_utf__utf16_to_utf8(&utf8_string, 861289177Speter (const void*)(src_string->data), 862289177Speter src_string->len / sizeof(apr_uint16_t), 863289177Speter TRUE, result_pool, result_pool); 864289177Speter break; 865289177Speter 866289177Speter case ASN1_UNIVERSAL_STRING: 867289177Speter if (0 != src_string->len % sizeof(apr_int32_t)) 868289177Speter return fuzzy_escape(src_string, result_pool); 869289177Speter err = svn_utf__utf32_to_utf8(&utf8_string, 870289177Speter (const void*)(src_string->data), 871289177Speter src_string->len / sizeof(apr_int32_t), 872289177Speter TRUE, result_pool, result_pool); 873289177Speter break; 874289177Speter 875289177Speter /* Despite what all the IETF, ISO, ITU bits say everything out 876289177Speter * on the Internet that I can find treats this as ISO-8859-1. 877289177Speter * Even the name is misleading, it's not actually T.61. All the 878289177Speter * gory details can be found in the Character Sets section of: 879289177Speter * https://www.cs.auckland.ac.nz/~pgut001/pubs/x509guide.txt 880289177Speter */ 881289177Speter case ASN1_T61_STRING: 882289177Speter err = latin1_to_utf8(&utf8_string, src_string, result_pool); 883289177Speter break; 884289177Speter 885289177Speter /* This leaves two types out there in the wild. PrintableString, 886289177Speter * which is just a subset of ASCII and IA5 which is ASCII (though 887289177Speter * 0x24 '$' and 0x23 '#' may be defined with differnet symbols 888289177Speter * depending on the location, in practice it seems everyone just 889289177Speter * treats it as ASCII). Since these are just ASCII run through 890289177Speter * the fuzzy_escape code to deal with anything that isn't actually 891289177Speter * ASCII. There shouldn't be any other types here but if we find 892289177Speter * a cert with some other encoding, the best we can do is the 893289177Speter * fuzzy_escape(). Note: Technically IA5 isn't valid in this 894289177Speter * context, however in the real world it may pop up. */ 895289177Speter default: 896289177Speter return fuzzy_escape(src_string, result_pool); 897289177Speter } 898289177Speter 899289177Speter if (err) 900289177Speter { 901289177Speter svn_error_clear(err); 902289177Speter return fuzzy_escape(src_string, result_pool); 903289177Speter } 904289177Speter 905289177Speter return nul_escape(utf8_string, result_pool); 906289177Speter} 907289177Speter 908289177Speterstatic svn_error_t * 909289177Speterx509_name_to_certinfo(apr_array_header_t **result, 910289177Speter const x509_name *dn, 911289177Speter apr_pool_t *scratch_pool, 912289177Speter apr_pool_t *result_pool) 913289177Speter{ 914289177Speter const x509_name *name = dn; 915289177Speter 916289177Speter *result = apr_array_make(result_pool, 6, sizeof(svn_x509_name_attr_t *)); 917289177Speter 918289177Speter while (name != NULL) { 919289177Speter svn_x509_name_attr_t *attr = apr_palloc(result_pool, sizeof(svn_x509_name_attr_t)); 920289177Speter 921289177Speter attr->oid_len = name->oid.len; 922289177Speter attr->oid = apr_palloc(result_pool, attr->oid_len); 923289177Speter memcpy(attr->oid, name->oid.p, attr->oid_len); 924289177Speter attr->utf8_value = x509name_to_utf8_string(name, result_pool); 925289177Speter if (!attr->utf8_value) 926289177Speter /* this should never happen */ 927289177Speter attr->utf8_value = apr_pstrdup(result_pool, "??"); 928289177Speter APR_ARRAY_PUSH(*result, const svn_x509_name_attr_t *) = attr; 929289177Speter 930289177Speter name = name->next; 931289177Speter } 932289177Speter 933289177Speter return SVN_NO_ERROR; 934289177Speter} 935289177Speter 936289177Speterstatic svn_boolean_t 937289177Speteris_hostname(const char *str) 938289177Speter{ 939289177Speter apr_size_t i, len = strlen(str); 940289177Speter 941289177Speter for (i = 0; i < len; i++) 942289177Speter { 943289177Speter char c = str[i]; 944289177Speter 945289177Speter /* '-' is only legal when not at the start or end of a label */ 946289177Speter if (c == '-') 947289177Speter { 948289177Speter if (i + 1 != len) 949289177Speter { 950289177Speter if (str[i + 1] == '.') 951289177Speter return FALSE; /* '-' preceeds a '.' */ 952289177Speter } 953289177Speter else 954289177Speter return FALSE; /* '-' is at end of string */ 955289177Speter 956289177Speter /* determine the previous character. */ 957289177Speter if (i == 0) 958289177Speter return FALSE; /* '-' is at start of string */ 959289177Speter else 960289177Speter if (str[i - 1] == '.') 961289177Speter return FALSE; /* '-' follows a '.' */ 962289177Speter } 963289177Speter else if (c != '*' && c != '.' && !svn_ctype_isalnum(c)) 964289177Speter return FALSE; /* some character not allowed */ 965289177Speter } 966289177Speter 967289177Speter return TRUE; 968289177Speter} 969289177Speter 970289177Speterstatic const char * 971289177Speterx509parse_get_cn(apr_array_header_t *subject) 972289177Speter{ 973289177Speter int i; 974289177Speter 975289177Speter for (i = 0; i < subject->nelts; ++i) 976289177Speter { 977289177Speter const svn_x509_name_attr_t *attr = APR_ARRAY_IDX(subject, i, const svn_x509_name_attr_t *); 978289177Speter if (equal(attr->oid, attr->oid_len, 979289177Speter SVN_X509_OID_COMMON_NAME, sizeof(SVN_X509_OID_COMMON_NAME) - 1)) 980289177Speter return attr->utf8_value; 981289177Speter } 982289177Speter 983289177Speter return NULL; 984289177Speter} 985289177Speter 986289177Speter 987289177Speterstatic void 988289177Speterx509parse_get_hostnames(svn_x509_certinfo_t *ci, x509_cert *crt, 989289177Speter apr_pool_t *result_pool, apr_pool_t *scratch_pool) 990289177Speter{ 991289177Speter ci->hostnames = NULL; 992289177Speter 993289177Speter if (crt->dnsnames->nelts > 0) 994289177Speter { 995289177Speter int i; 996289177Speter 997289177Speter ci->hostnames = apr_array_make(result_pool, crt->dnsnames->nelts, 998289177Speter sizeof(const char*)); 999289177Speter 1000289177Speter /* Subject Alt Names take priority */ 1001289177Speter for (i = 0; i < crt->dnsnames->nelts; i++) 1002289177Speter { 1003289177Speter x509_buf *dnsname = APR_ARRAY_IDX(crt->dnsnames, i, x509_buf *); 1004289177Speter const svn_string_t *temp = svn_string_ncreate((const char *)dnsname->p, 1005289177Speter dnsname->len, 1006289177Speter scratch_pool); 1007289177Speter 1008289177Speter APR_ARRAY_PUSH(ci->hostnames, const char*) 1009289177Speter = fuzzy_escape(temp, result_pool); 1010289177Speter } 1011289177Speter } 1012289177Speter else 1013289177Speter { 1014289177Speter /* no SAN then get the hostname from the CommonName on the cert */ 1015289177Speter const char *utf8_value; 1016289177Speter 1017289177Speter utf8_value = x509parse_get_cn(ci->subject); 1018289177Speter 1019289177Speter if (utf8_value && is_hostname(utf8_value)) 1020289177Speter { 1021289177Speter ci->hostnames = apr_array_make(result_pool, 1, sizeof(const char*)); 1022289177Speter APR_ARRAY_PUSH(ci->hostnames, const char*) = utf8_value; 1023289177Speter } 1024289177Speter } 1025289177Speter} 1026289177Speter 1027289177Speter/* 1028289177Speter * Parse one certificate. 1029289177Speter */ 1030289177Spetersvn_error_t * 1031289177Spetersvn_x509_parse_cert(svn_x509_certinfo_t **certinfo, 1032289177Speter const char *buf, 1033289177Speter apr_size_t buflen, 1034289177Speter apr_pool_t *result_pool, 1035289177Speter apr_pool_t *scratch_pool) 1036289177Speter{ 1037289177Speter svn_error_t *err; 1038289177Speter ptrdiff_t len; 1039289177Speter const unsigned char *p; 1040289177Speter const unsigned char *end; 1041289177Speter x509_cert *crt; 1042289177Speter svn_x509_certinfo_t *ci; 1043289177Speter 1044289177Speter crt = apr_pcalloc(scratch_pool, sizeof(*crt)); 1045289177Speter p = (const unsigned char *)buf; 1046289177Speter len = buflen; 1047289177Speter end = p + len; 1048289177Speter 1049289177Speter /* 1050289177Speter * Certificate ::= SEQUENCE { 1051289177Speter * tbsCertificate TBSCertificate, 1052289177Speter * signatureAlgorithm AlgorithmIdentifier, 1053289177Speter * signatureValue BIT STRING } 1054289177Speter */ 1055289177Speter err = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE); 1056289177Speter if (err) 1057289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_FORMAT, err, NULL); 1058289177Speter 1059289177Speter if (len != (end - p)) 1060289177Speter { 1061289177Speter err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL); 1062289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_FORMAT, err, NULL); 1063289177Speter } 1064289177Speter 1065289177Speter /* 1066289177Speter * TBSCertificate ::= SEQUENCE { 1067289177Speter */ 1068289177Speter err = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE); 1069289177Speter if (err) 1070289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_FORMAT, err, NULL); 1071289177Speter 1072289177Speter end = p + len; 1073289177Speter 1074289177Speter /* 1075289177Speter * Version ::= INTEGER { v1(0), v2(1), v3(2) } 1076289177Speter * 1077289177Speter * CertificateSerialNumber ::= INTEGER 1078289177Speter * 1079289177Speter * signature AlgorithmIdentifier 1080289177Speter */ 1081289177Speter SVN_ERR(x509_get_version(&p, end, &crt->version)); 1082289177Speter SVN_ERR(x509_get_serial(&p, end, &crt->serial)); 1083289177Speter SVN_ERR(x509_get_alg(&p, end, &crt->sig_oid1)); 1084289177Speter 1085289177Speter crt->version++; 1086289177Speter 1087289177Speter if (crt->version > 3) 1088289177Speter return svn_error_create(SVN_ERR_X509_CERT_UNKNOWN_VERSION, NULL, NULL); 1089289177Speter 1090289177Speter /* 1091289177Speter * issuer Name 1092289177Speter */ 1093289177Speter err = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE); 1094289177Speter if (err) 1095289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_FORMAT, err, NULL); 1096289177Speter 1097289177Speter SVN_ERR(x509_get_name(&p, p + len, &crt->issuer, scratch_pool)); 1098289177Speter 1099289177Speter /* 1100289177Speter * Validity ::= SEQUENCE { 1101289177Speter * notBefore Time, 1102289177Speter * notAfter Time } 1103289177Speter * 1104289177Speter */ 1105289177Speter SVN_ERR(x509_get_dates(&crt->valid_from, &crt->valid_to, &p, end, 1106289177Speter scratch_pool)); 1107289177Speter 1108289177Speter /* 1109289177Speter * subject Name 1110289177Speter */ 1111289177Speter err = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE); 1112289177Speter if (err) 1113289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_FORMAT, err, NULL); 1114289177Speter 1115289177Speter SVN_ERR(x509_get_name(&p, p + len, &crt->subject, scratch_pool)); 1116289177Speter 1117289177Speter /* 1118289177Speter * SubjectPublicKeyInfo ::= SEQUENCE 1119289177Speter * algorithm AlgorithmIdentifier, 1120289177Speter * subjectPublicKey BIT STRING } 1121289177Speter */ 1122289177Speter err = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE); 1123289177Speter if (err) 1124289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_FORMAT, err, NULL); 1125289177Speter 1126289177Speter /* Skip pubkey. */ 1127289177Speter p += len; 1128289177Speter 1129289177Speter /* 1130289177Speter * issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, 1131289177Speter * -- If present, version shall be v2 or v3 1132289177Speter * subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, 1133289177Speter * -- If present, version shall be v2 or v3 1134289177Speter * extensions [3] EXPLICIT Extensions OPTIONAL 1135289177Speter * -- If present, version shall be v3 1136289177Speter */ 1137289177Speter crt->dnsnames = apr_array_make(scratch_pool, 3, sizeof(x509_buf *)); 1138289177Speter 1139289177Speter /* Try to parse issuerUniqueID, subjectUniqueID and extensions for *every* 1140289177Speter * version (X.509 v1, v2 and v3), not just v2 or v3. If they aren't present, 1141289177Speter * we are fine, but we don't want to throw an error if they are. v1 and v2 1142289177Speter * certificates with the corresponding extra fields are ill-formed per RFC 1143289177Speter * 5280 s. 4.1, but we suspect they could exist in the real world. Other 1144289177Speter * X.509 parsers (e.g., within OpenSSL or Microsoft CryptoAPI) aren't picky 1145289177Speter * about these certificates, and we also allow them. */ 1146289177Speter SVN_ERR(x509_get_uid(&p, end, &crt->issuer_id, 1)); 1147289177Speter SVN_ERR(x509_get_uid(&p, end, &crt->subject_id, 2)); 1148289177Speter SVN_ERR(x509_get_ext(crt->dnsnames, &p, end)); 1149289177Speter 1150289177Speter if (p != end) 1151289177Speter { 1152289177Speter err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL); 1153289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_FORMAT, err, NULL); 1154289177Speter } 1155289177Speter 1156289177Speter end = (const unsigned char*) buf + buflen; 1157289177Speter 1158289177Speter /* 1159289177Speter * signatureAlgorithm AlgorithmIdentifier, 1160289177Speter * signatureValue BIT STRING 1161289177Speter */ 1162289177Speter SVN_ERR(x509_get_alg(&p, end, &crt->sig_oid2)); 1163289177Speter 1164289177Speter if (!oids_equal(&crt->sig_oid1, &crt->sig_oid2)) 1165289177Speter return svn_error_create(SVN_ERR_X509_CERT_SIG_MISMATCH, NULL, NULL); 1166289177Speter 1167289177Speter SVN_ERR(x509_get_sig(&p, end, &crt->sig)); 1168289177Speter 1169289177Speter if (p != end) 1170289177Speter { 1171289177Speter err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL); 1172289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_FORMAT, err, NULL); 1173289177Speter } 1174289177Speter 1175289177Speter ci = apr_pcalloc(result_pool, sizeof(*ci)); 1176289177Speter 1177289177Speter /* Get the subject name */ 1178289177Speter SVN_ERR(x509_name_to_certinfo(&ci->subject, &crt->subject, 1179289177Speter scratch_pool, result_pool)); 1180289177Speter 1181289177Speter /* Get the issuer name */ 1182289177Speter SVN_ERR(x509_name_to_certinfo(&ci->issuer, &crt->issuer, 1183289177Speter scratch_pool, result_pool)); 1184289177Speter 1185289177Speter /* Copy the validity range */ 1186289177Speter ci->valid_from = crt->valid_from; 1187289177Speter ci->valid_to = crt->valid_to; 1188289177Speter 1189289177Speter /* Calculate the SHA1 digest of the certificate, otherwise known as 1190289177Speter the fingerprint */ 1191289177Speter SVN_ERR(svn_checksum(&ci->digest, svn_checksum_sha1, buf, buflen, 1192289177Speter result_pool)); 1193289177Speter 1194289177Speter /* Construct the array of host names */ 1195289177Speter x509parse_get_hostnames(ci, crt, result_pool, scratch_pool); 1196289177Speter 1197289177Speter *certinfo = ci; 1198289177Speter return SVN_NO_ERROR; 1199289177Speter} 1200289177Speter 1201