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 266362181Sdim /* The OID encoding of 1.2.840.113549.1.1.10 (id-RSASSA-PSS) */ 267362181Sdim#define OID_RSASSA_PSS "\x2a\x86\x48\x86\xf7\x0d\x01\x01\x0a" 268289177Speter 269362181Sdim if (equal(alg->p, alg->len, OID_RSASSA_PSS, sizeof(OID_RSASSA_PSS) - 1)) 270362181Sdim { 271362181Sdim /* Skip over algorithm parameters for id-RSASSA-PSS (RFC 8017) 272362181Sdim * 273362181Sdim * RSASSA-PSS-params ::= SEQUENCE { 274362181Sdim * hashAlgorithm [0] HashAlgorithm DEFAULT sha1, 275362181Sdim * maskGenAlgorithm [1] MaskGenAlgorithm DEFAULT mgf1SHA1, 276362181Sdim * saltLength [2] INTEGER DEFAULT 20, 277362181Sdim * trailerField [3] TrailerField DEFAULT trailerFieldBC 278362181Sdim * } 279362181Sdim */ 280362181Sdim err = asn1_get_tag(p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE); 281362181Sdim if (err) 282362181Sdim return svn_error_create(SVN_ERR_X509_CERT_INVALID_ALG, err, NULL); 283362181Sdim 284362181Sdim *p += len; 285362181Sdim } 286362181Sdim else 287362181Sdim { 288362181Sdim /* Algorithm parameters must be NULL for other algorithms */ 289362181Sdim err = asn1_get_tag(p, end, &len, ASN1_NULL); 290362181Sdim if (err) 291362181Sdim return svn_error_create(SVN_ERR_X509_CERT_INVALID_ALG, err, NULL); 292362181Sdim } 293362181Sdim 294289177Speter if (*p != end) 295289177Speter { 296289177Speter err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL); 297289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_ALG, err, NULL); 298289177Speter } 299289177Speter 300289177Speter return SVN_NO_ERROR; 301289177Speter} 302289177Speter 303289177Speter/* 304289177Speter * AttributeTypeAndValue ::= SEQUENCE { 305289177Speter * type AttributeType, 306289177Speter * value AttributeValue } 307289177Speter * 308289177Speter * AttributeType ::= OBJECT IDENTIFIER 309289177Speter * 310289177Speter * AttributeValue ::= ANY DEFINED BY AttributeType 311289177Speter */ 312289177Speterstatic svn_error_t * 313289177Speterx509_get_attribute(const unsigned char **p, const unsigned char *end, 314289177Speter x509_name *cur, apr_pool_t *result_pool) 315289177Speter{ 316289177Speter svn_error_t *err; 317289177Speter ptrdiff_t len; 318289177Speter x509_buf *oid; 319289177Speter x509_buf *val; 320289177Speter 321289177Speter err = asn1_get_tag(p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE); 322289177Speter if (err) 323289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_NAME, err, NULL); 324289177Speter 325289177Speter end = *p + len; 326289177Speter 327289177Speter oid = &cur->oid; 328289177Speter 329289177Speter err = asn1_get_tag(p, end, &oid->len, ASN1_OID); 330289177Speter if (err) 331289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_NAME, err, NULL); 332289177Speter 333289177Speter oid->tag = ASN1_OID; 334289177Speter oid->p = *p; 335289177Speter *p += oid->len; 336289177Speter 337289177Speter if ((end - *p) < 1) 338289177Speter { 339289177Speter err = svn_error_create(SVN_ERR_ASN1_OUT_OF_DATA, NULL, NULL); 340289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_NAME, err, NULL); 341289177Speter } 342289177Speter 343289177Speter if (**p != ASN1_BMP_STRING && **p != ASN1_UTF8_STRING && 344289177Speter **p != ASN1_T61_STRING && **p != ASN1_PRINTABLE_STRING && 345289177Speter **p != ASN1_IA5_STRING && **p != ASN1_UNIVERSAL_STRING) 346289177Speter { 347289177Speter err = svn_error_create(SVN_ERR_ASN1_UNEXPECTED_TAG, NULL, NULL); 348289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_NAME, err, NULL); 349289177Speter } 350289177Speter 351289177Speter val = &cur->val; 352289177Speter val->tag = *(*p)++; 353289177Speter 354289177Speter err = asn1_get_len(p, end, &val->len); 355289177Speter if (err) 356289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_NAME, err, NULL); 357289177Speter 358289177Speter val->p = *p; 359289177Speter *p += val->len; 360289177Speter 361289177Speter cur->next = NULL; 362289177Speter 363289177Speter if (*p != end) 364289177Speter { 365289177Speter err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL); 366289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_NAME, err, NULL); 367289177Speter } 368289177Speter 369289177Speter return SVN_NO_ERROR; 370289177Speter} 371289177Speter 372289177Speter/* 373289177Speter * RelativeDistinguishedName ::= 374289177Speter * SET SIZE (1..MAX) OF AttributeTypeAndValue 375289177Speter */ 376289177Speterstatic svn_error_t * 377289177Speterx509_get_name(const unsigned char **p, const unsigned char *name_end, 378289177Speter x509_name *name, apr_pool_t *result_pool) 379289177Speter{ 380289177Speter svn_error_t *err; 381289177Speter ptrdiff_t len; 382289177Speter const unsigned char *set_end; 383289177Speter x509_name *cur = NULL; 384289177Speter 385289177Speter err = asn1_get_tag(p, name_end, &len, ASN1_CONSTRUCTED | ASN1_SET); 386362181Sdim if (err || len < 1) 387289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_NAME, err, NULL); 388289177Speter 389289177Speter set_end = *p + len; 390289177Speter 391289177Speter /* 392289177Speter * iterate until the end of the SET is reached 393289177Speter */ 394289177Speter while (*p < set_end) 395289177Speter { 396289177Speter if (!cur) 397289177Speter { 398289177Speter cur = name; 399289177Speter } 400289177Speter else 401289177Speter { 402289177Speter cur->next = apr_palloc(result_pool, sizeof(x509_name)); 403289177Speter cur = cur->next; 404289177Speter } 405289177Speter SVN_ERR(x509_get_attribute(p, set_end, cur, result_pool)); 406289177Speter } 407289177Speter 408289177Speter /* 409289177Speter * recurse until end of SEQUENCE (name) is reached 410289177Speter */ 411289177Speter if (*p == name_end) 412289177Speter return SVN_NO_ERROR; 413289177Speter 414289177Speter cur->next = apr_palloc(result_pool, sizeof(x509_name)); 415289177Speter 416289177Speter return svn_error_trace(x509_get_name(p, name_end, cur->next, result_pool)); 417289177Speter} 418289177Speter 419289177Speter/* Retrieve the date from the X.509 cert data between *P and END in either 420289177Speter * UTCTime or GeneralizedTime format (as defined in RFC 5280 s. 4.1.2.5.1 and 421289177Speter * 4.1.2.5.2 respectively) and place the result in WHEN using SCRATCH_POOL 422289177Speter * for temporary allocations. */ 423289177Speterstatic svn_error_t * 424289177Speterx509_get_date(apr_time_t *when, 425289177Speter const unsigned char **p, 426289177Speter const unsigned char *end, 427289177Speter apr_pool_t *scratch_pool) 428289177Speter{ 429289177Speter svn_error_t *err; 430289177Speter apr_status_t ret; 431289177Speter int tag; 432289177Speter ptrdiff_t len; 433289177Speter char *date; 434289177Speter apr_time_exp_t xt = { 0 }; 435289177Speter char tz; 436289177Speter 437289177Speter err = asn1_get_tag(p, end, &len, ASN1_UTC_TIME); 438289177Speter if (err && err->apr_err == SVN_ERR_ASN1_UNEXPECTED_TAG) 439289177Speter { 440289177Speter svn_error_clear(err); 441289177Speter err = asn1_get_tag(p, end, &len, ASN1_GENERALIZED_TIME); 442289177Speter tag = ASN1_GENERALIZED_TIME; 443289177Speter } 444289177Speter else 445289177Speter { 446289177Speter tag = ASN1_UTC_TIME; 447289177Speter } 448289177Speter if (err) 449289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_DATE, err, NULL); 450289177Speter 451289177Speter date = apr_pstrndup(scratch_pool, (const char *) *p, len); 452289177Speter switch (tag) 453289177Speter { 454289177Speter case ASN1_UTC_TIME: 455289177Speter if (sscanf(date, "%2d%2d%2d%2d%2d%2d%c", 456289177Speter &xt.tm_year, &xt.tm_mon, &xt.tm_mday, 457289177Speter &xt.tm_hour, &xt.tm_min, &xt.tm_sec, &tz) < 6) 458289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_DATE, NULL, NULL); 459289177Speter 460289177Speter /* UTCTime only provides a 2 digit year. X.509 specifies that years 461289177Speter * greater than or equal to 50 must be interpreted as 19YY and years 462289177Speter * less than 50 be interpreted as 20YY. This format is not used for 463289177Speter * years greater than 2049. apr_time_exp_t wants years as the number 464289177Speter * of years since 1900, so don't convert to 4 digits here. */ 465289177Speter xt.tm_year += 100 * (xt.tm_year < 50); 466289177Speter break; 467289177Speter 468289177Speter case ASN1_GENERALIZED_TIME: 469289177Speter if (sscanf(date, "%4d%2d%2d%2d%2d%2d%c", 470289177Speter &xt.tm_year, &xt.tm_mon, &xt.tm_mday, 471289177Speter &xt.tm_hour, &xt.tm_min, &xt.tm_sec, &tz) < 6) 472289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_DATE, NULL, NULL); 473289177Speter 474289177Speter /* GeneralizedTime has the full 4 digit year. But apr_time_exp_t 475289177Speter * wants years as the number of years since 1900. */ 476289177Speter xt.tm_year -= 1900; 477289177Speter break; 478289177Speter 479289177Speter default: 480289177Speter /* shouldn't ever get here because we should error out above in the 481289177Speter * asn1_get_tag() bits but doesn't hurt to be extra paranoid. */ 482289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_DATE, NULL, NULL); 483289177Speter break; 484289177Speter } 485289177Speter 486289177Speter /* check that the timezone is GMT 487289177Speter * ASN.1 allows for the timezone to be specified but X.509 says it must 488289177Speter * always be GMT. A little bit of extra paranoia here seems like a good 489289177Speter * idea. */ 490289177Speter if (tz != 'Z') 491289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_DATE, NULL, NULL); 492289177Speter 493289177Speter /* apr_time_exp_t expects months to be zero indexed, 0=Jan, 11=Dec. */ 494289177Speter xt.tm_mon -= 1; 495289177Speter 496362181Sdim /* range checks (as per definition of apr_time_exp_t in apr_time.h) */ 497362181Sdim if (xt.tm_usec < 0 || 498362181Sdim xt.tm_sec < 0 || xt.tm_sec > 61 || 499362181Sdim xt.tm_min < 0 || xt.tm_min > 59 || 500362181Sdim xt.tm_hour < 0 || xt.tm_hour > 23 || 501362181Sdim xt.tm_mday < 1 || xt.tm_mday > 31 || 502362181Sdim xt.tm_mon < 0 || xt.tm_mon > 11 || 503362181Sdim xt.tm_year < 0 || 504362181Sdim xt.tm_wday < 0 || xt.tm_wday > 6 || 505362181Sdim xt.tm_yday < 0 || xt.tm_yday > 365) 506362181Sdim return svn_error_create(SVN_ERR_X509_CERT_INVALID_DATE, NULL, NULL); 507362181Sdim 508289177Speter ret = apr_time_exp_gmt_get(when, &xt); 509289177Speter if (ret) 510289177Speter return svn_error_wrap_apr(ret, NULL); 511289177Speter 512289177Speter *p += len; 513289177Speter 514289177Speter return SVN_NO_ERROR; 515289177Speter} 516289177Speter 517289177Speter/* 518289177Speter * Validity ::= SEQUENCE { 519289177Speter * notBefore Time, 520289177Speter * notAfter Time } 521289177Speter * 522289177Speter * Time ::= CHOICE { 523289177Speter * utcTime UTCTime, 524289177Speter * generalTime GeneralizedTime } 525289177Speter */ 526289177Speterstatic svn_error_t * 527289177Speterx509_get_dates(apr_time_t *from, 528289177Speter apr_time_t *to, 529289177Speter const unsigned char **p, 530289177Speter const unsigned char *end, 531289177Speter apr_pool_t *scratch_pool) 532289177Speter{ 533289177Speter svn_error_t *err; 534289177Speter ptrdiff_t len; 535289177Speter 536289177Speter err = asn1_get_tag(p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE); 537289177Speter if (err) 538289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_DATE, err, NULL); 539289177Speter 540289177Speter end = *p + len; 541289177Speter 542289177Speter SVN_ERR(x509_get_date(from, p, end, scratch_pool)); 543289177Speter 544289177Speter SVN_ERR(x509_get_date(to, p, end, scratch_pool)); 545289177Speter 546289177Speter if (*p != end) 547289177Speter { 548289177Speter err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL); 549289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_DATE, err, NULL); 550289177Speter } 551289177Speter 552289177Speter return SVN_NO_ERROR; 553289177Speter} 554289177Speter 555289177Speterstatic svn_error_t * 556289177Speterx509_get_sig(const unsigned char **p, const unsigned char *end, x509_buf * sig) 557289177Speter{ 558289177Speter svn_error_t *err; 559289177Speter ptrdiff_t len; 560289177Speter 561289177Speter err = asn1_get_tag(p, end, &len, ASN1_BIT_STRING); 562289177Speter if (err) 563289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_SIGNATURE, err, NULL); 564289177Speter 565289177Speter sig->tag = ASN1_BIT_STRING; 566289177Speter 567289177Speter if (--len < 1 || *(*p)++ != 0) 568289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_SIGNATURE, NULL, NULL); 569289177Speter 570289177Speter sig->len = len; 571289177Speter sig->p = *p; 572289177Speter 573289177Speter *p += len; 574289177Speter 575289177Speter return SVN_NO_ERROR; 576289177Speter} 577289177Speter 578289177Speter/* 579289177Speter * X.509 v2/v3 unique identifier (not parsed) 580289177Speter */ 581289177Speterstatic svn_error_t * 582289177Speterx509_get_uid(const unsigned char **p, 583289177Speter const unsigned char *end, x509_buf * uid, int n) 584289177Speter{ 585289177Speter svn_error_t *err; 586289177Speter 587289177Speter if (*p == end) 588289177Speter return SVN_NO_ERROR; 589289177Speter 590289177Speter err = asn1_get_tag(p, end, &uid->len, 591289177Speter ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | n); 592289177Speter if (err) 593289177Speter { 594289177Speter if (err->apr_err == SVN_ERR_ASN1_UNEXPECTED_TAG) 595289177Speter { 596289177Speter svn_error_clear(err); 597289177Speter return SVN_NO_ERROR; 598289177Speter } 599289177Speter 600289177Speter return svn_error_trace(err); 601289177Speter } 602289177Speter 603289177Speter uid->tag = ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | n; 604289177Speter uid->p = *p; 605289177Speter *p += uid->len; 606289177Speter 607289177Speter return SVN_NO_ERROR; 608289177Speter} 609289177Speter 610289177Speter/* 611289177Speter * X.509 v3 extensions (not parsed) 612289177Speter */ 613289177Speterstatic svn_error_t * 614289177Speterx509_get_ext(apr_array_header_t *dnsnames, 615289177Speter const unsigned char **p, 616289177Speter const unsigned char *end) 617289177Speter{ 618289177Speter svn_error_t *err; 619289177Speter ptrdiff_t len; 620289177Speter 621289177Speter if (*p == end) 622289177Speter return SVN_NO_ERROR; 623289177Speter 624289177Speter err = asn1_get_tag(p, end, &len, 625289177Speter ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 3); 626289177Speter if (err) 627289177Speter { 628289177Speter /* If there aren't extensions that's ok they aren't required */ 629289177Speter if (err->apr_err == SVN_ERR_ASN1_UNEXPECTED_TAG) 630289177Speter { 631289177Speter svn_error_clear(err); 632289177Speter return SVN_NO_ERROR; 633289177Speter } 634289177Speter 635289177Speter return svn_error_trace(err); 636289177Speter } 637289177Speter 638289177Speter end = *p + len; 639289177Speter 640289177Speter SVN_ERR(asn1_get_tag(p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE)); 641289177Speter 642289177Speter if (end != *p + len) 643289177Speter { 644289177Speter err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL); 645289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_EXTENSIONS, err, NULL); 646289177Speter } 647289177Speter 648289177Speter while (*p < end) 649289177Speter { 650289177Speter ptrdiff_t ext_len; 651289177Speter const unsigned char *ext_start, *sna_end; 652289177Speter err = asn1_get_tag(p, end, &ext_len, ASN1_CONSTRUCTED | ASN1_SEQUENCE); 653289177Speter if (err) 654289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_EXTENSIONS, err, 655289177Speter NULL); 656289177Speter ext_start = *p; 657289177Speter 658289177Speter err = asn1_get_tag(p, end, &len, ASN1_OID); 659289177Speter if (err) 660289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_EXTENSIONS, err, 661289177Speter NULL); 662289177Speter 663289177Speter /* skip all extensions except SubjectAltName */ 664289177Speter if (!equal(*p, len, 665289177Speter OID_SUBJECT_ALT_NAME, sizeof(OID_SUBJECT_ALT_NAME) - 1)) 666289177Speter { 667289177Speter *p += ext_len - (*p - ext_start); 668289177Speter continue; 669289177Speter } 670289177Speter *p += len; 671289177Speter 672289177Speter err = asn1_get_tag(p, end, &len, ASN1_OCTET_STRING); 673289177Speter if (err) 674289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_EXTENSIONS, err, 675289177Speter NULL); 676289177Speter 677289177Speter /* SubjectAltName ::= GeneralNames 678289177Speter 679289177Speter GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName 680289177Speter 681289177Speter GeneralName ::= CHOICE { 682289177Speter other Name [0] OtherName, 683289177Speter rfc822Name [1] IA5String, 684289177Speter dNSName [2] IA5String, 685289177Speter x400Address [3] ORAddress, 686289177Speter directoryName [4] Name, 687289177Speter ediPartyName [5] EDIPartyName, 688289177Speter uniformResourceIdentifier [6] IA5String, 689289177Speter iPAddress [7] OCTET STRING, 690289177Speter registeredID [8] OBJECT IDENTIFIER } */ 691289177Speter sna_end = *p + len; 692289177Speter 693289177Speter err = asn1_get_tag(p, sna_end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE); 694289177Speter if (err) 695289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_EXTENSIONS, err, 696289177Speter NULL); 697289177Speter 698289177Speter if (sna_end != *p + len) 699289177Speter { 700289177Speter err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL); 701289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_EXTENSIONS, err, NULL); 702289177Speter } 703289177Speter 704289177Speter while (*p < sna_end) 705289177Speter { 706289177Speter err = asn1_get_tag(p, sna_end, &len, ASN1_CONTEXT_SPECIFIC | 707289177Speter ASN1_PRIMITIVE | 2); 708289177Speter if (err) 709289177Speter { 710289177Speter /* not not a dNSName */ 711289177Speter if (err->apr_err == SVN_ERR_ASN1_UNEXPECTED_TAG) 712289177Speter { 713289177Speter svn_error_clear(err); 714289177Speter /* need to skip the tag and then find the length to 715289177Speter * skip to ignore this SNA entry. */ 716289177Speter (*p)++; 717289177Speter SVN_ERR(asn1_get_len(p, sna_end, &len)); 718289177Speter *p += len; 719289177Speter continue; 720289177Speter } 721289177Speter 722289177Speter return svn_error_trace(err); 723289177Speter } 724289177Speter else 725289177Speter { 726289177Speter /* We found a dNSName entry */ 727362181Sdim x509_buf *dnsname = apr_palloc(dnsnames->pool, sizeof(*dnsname)); 728289177Speter dnsname->tag = ASN1_IA5_STRING; /* implicit based on dNSName */ 729289177Speter dnsname->len = len; 730289177Speter dnsname->p = *p; 731289177Speter APR_ARRAY_PUSH(dnsnames, x509_buf *) = dnsname; 732289177Speter } 733289177Speter 734289177Speter *p += len; 735289177Speter } 736289177Speter 737289177Speter } 738289177Speter 739289177Speter return SVN_NO_ERROR; 740289177Speter} 741289177Speter 742289177Speter/* Escape all non-ascii or control characters similar to 743289177Speter * svn_xml_fuzzy_escape() and svn_utf_cstring_from_utf8_fuzzy(). 744289177Speter * All of the encoding formats somewhat overlap with ascii (BMPString 745289177Speter * and UniversalString are actually always wider so you'll end up 746289177Speter * with a bunch of escaped nul bytes, but ideally we don't get here 747289177Speter * for those). The result is always a nul-terminated C string. */ 748289177Speterstatic const char * 749289177Speterfuzzy_escape(const svn_string_t *src, apr_pool_t *result_pool) 750289177Speter{ 751289177Speter const char *end = src->data + src->len; 752289177Speter const char *p = src->data, *q; 753289177Speter svn_stringbuf_t *outstr; 754289177Speter char escaped_char[6]; /* ? \ u u u \0 */ 755289177Speter 756289177Speter for (q = p; q < end; q++) 757289177Speter { 758289177Speter if (!svn_ctype_isascii(*q) || svn_ctype_iscntrl(*q)) 759289177Speter break; 760289177Speter } 761289177Speter 762289177Speter if (q == end) 763289177Speter return src->data; 764289177Speter 765289177Speter outstr = svn_stringbuf_create_empty(result_pool); 766289177Speter while (1) 767289177Speter { 768289177Speter q = p; 769289177Speter 770289177Speter /* Traverse till either unsafe character or eos. */ 771289177Speter while (q < end && svn_ctype_isascii(*q) && !svn_ctype_iscntrl(*q)) 772289177Speter q++; 773289177Speter 774289177Speter /* copy chunk before marker */ 775289177Speter svn_stringbuf_appendbytes(outstr, p, q - p); 776289177Speter 777289177Speter if (q == end) 778289177Speter break; 779289177Speter 780289177Speter apr_snprintf(escaped_char, sizeof(escaped_char), "?\\%03u", 781289177Speter (unsigned char) *q); 782289177Speter svn_stringbuf_appendcstr(outstr, escaped_char); 783289177Speter 784289177Speter p = q + 1; 785289177Speter } 786289177Speter 787289177Speter return outstr->data; 788289177Speter} 789289177Speter 790289177Speter/* Escape only NUL characters from a string that is presumed to 791289177Speter * be UTF-8 encoded and return a nul-terminated C string. */ 792289177Speterstatic const char * 793289177Speternul_escape(const svn_string_t *src, apr_pool_t *result_pool) 794289177Speter{ 795289177Speter const char *end = src->data + src->len; 796289177Speter const char *p = src->data, *q; 797289177Speter svn_stringbuf_t *outstr; 798289177Speter 799289177Speter for (q = p; q < end; q++) 800289177Speter { 801289177Speter if (*q == '\0') 802289177Speter break; 803289177Speter } 804289177Speter 805289177Speter if (q == end) 806289177Speter return src->data; 807289177Speter 808289177Speter outstr = svn_stringbuf_create_empty(result_pool); 809289177Speter while (1) 810289177Speter { 811289177Speter q = p; 812289177Speter 813289177Speter /* Traverse till either unsafe character or eos. */ 814289177Speter while (q < end && *q != '\0') 815289177Speter q++; 816289177Speter 817289177Speter /* copy chunk before marker */ 818289177Speter svn_stringbuf_appendbytes(outstr, p, q - p); 819289177Speter 820289177Speter if (q == end) 821289177Speter break; 822289177Speter 823289177Speter svn_stringbuf_appendcstr(outstr, "?\\000"); 824289177Speter 825289177Speter p = q + 1; 826289177Speter } 827289177Speter 828289177Speter return outstr->data; 829289177Speter} 830289177Speter 831289177Speter 832289177Speter/* Convert an ISO-8859-1 (Latin-1) string to UTF-8. 833289177Speter ISO-8859-1 is a strict subset of Unicode. */ 834289177Speterstatic svn_error_t * 835289177Speterlatin1_to_utf8(const svn_string_t **result, const svn_string_t *src, 836289177Speter apr_pool_t *result_pool) 837289177Speter{ 838289177Speter apr_int32_t *ucs4buf; 839289177Speter svn_membuf_t resultbuf; 840289177Speter apr_size_t length; 841289177Speter apr_size_t i; 842289177Speter svn_string_t *res; 843289177Speter 844289177Speter ucs4buf = apr_palloc(result_pool, src->len * sizeof(*ucs4buf)); 845289177Speter for (i = 0; i < src->len; ++i) 846289177Speter ucs4buf[i] = (unsigned char)(src->data[i]); 847289177Speter 848289177Speter svn_membuf__create(&resultbuf, 2 * src->len, result_pool); 849289177Speter SVN_ERR(svn_utf__encode_ucs4_string( 850289177Speter &resultbuf, ucs4buf, src->len, &length)); 851289177Speter 852289177Speter res = apr_palloc(result_pool, sizeof(*res)); 853289177Speter res->data = resultbuf.data; 854289177Speter res->len = length; 855289177Speter *result = res; 856289177Speter return SVN_NO_ERROR; 857289177Speter} 858289177Speter 859289177Speter/* Make a best effort to convert a X.509 name to a UTF-8 encoded 860289177Speter * string and return it. If we can't properly convert just do a 861289177Speter * fuzzy conversion so we have something to display. */ 862289177Speterstatic const char * 863289177Speterx509name_to_utf8_string(const x509_name *name, apr_pool_t *result_pool) 864289177Speter{ 865289177Speter const svn_string_t *src_string; 866289177Speter const svn_string_t *utf8_string; 867289177Speter svn_error_t *err; 868289177Speter 869289177Speter src_string = svn_string_ncreate((const char *)name->val.p, 870289177Speter name->val.len, 871289177Speter result_pool); 872289177Speter switch (name->val.tag) 873289177Speter { 874289177Speter case ASN1_UTF8_STRING: 875289177Speter if (svn_utf__is_valid(src_string->data, src_string->len)) 876289177Speter return nul_escape(src_string, result_pool); 877289177Speter else 878289177Speter /* not a valid UTF-8 string, who knows what it is, 879289177Speter * so run it through the fuzzy_escape code. */ 880289177Speter return fuzzy_escape(src_string, result_pool); 881289177Speter break; 882289177Speter 883289177Speter /* Both BMP and UNIVERSAL should always be in Big Endian (aka 884289177Speter * network byte order). But rumor has it that there are certs 885289177Speter * out there with other endianess and even Byte Order Marks. 886289177Speter * If we actually run into these, we might need to do something 887289177Speter * about it. */ 888289177Speter 889289177Speter case ASN1_BMP_STRING: 890289177Speter if (0 != src_string->len % sizeof(apr_uint16_t)) 891289177Speter return fuzzy_escape(src_string, result_pool); 892289177Speter err = svn_utf__utf16_to_utf8(&utf8_string, 893289177Speter (const void*)(src_string->data), 894289177Speter src_string->len / sizeof(apr_uint16_t), 895289177Speter TRUE, result_pool, result_pool); 896289177Speter break; 897289177Speter 898289177Speter case ASN1_UNIVERSAL_STRING: 899289177Speter if (0 != src_string->len % sizeof(apr_int32_t)) 900289177Speter return fuzzy_escape(src_string, result_pool); 901289177Speter err = svn_utf__utf32_to_utf8(&utf8_string, 902289177Speter (const void*)(src_string->data), 903289177Speter src_string->len / sizeof(apr_int32_t), 904289177Speter TRUE, result_pool, result_pool); 905289177Speter break; 906289177Speter 907289177Speter /* Despite what all the IETF, ISO, ITU bits say everything out 908289177Speter * on the Internet that I can find treats this as ISO-8859-1. 909289177Speter * Even the name is misleading, it's not actually T.61. All the 910289177Speter * gory details can be found in the Character Sets section of: 911289177Speter * https://www.cs.auckland.ac.nz/~pgut001/pubs/x509guide.txt 912289177Speter */ 913289177Speter case ASN1_T61_STRING: 914289177Speter err = latin1_to_utf8(&utf8_string, src_string, result_pool); 915289177Speter break; 916289177Speter 917289177Speter /* This leaves two types out there in the wild. PrintableString, 918289177Speter * which is just a subset of ASCII and IA5 which is ASCII (though 919289177Speter * 0x24 '$' and 0x23 '#' may be defined with differnet symbols 920289177Speter * depending on the location, in practice it seems everyone just 921289177Speter * treats it as ASCII). Since these are just ASCII run through 922289177Speter * the fuzzy_escape code to deal with anything that isn't actually 923289177Speter * ASCII. There shouldn't be any other types here but if we find 924289177Speter * a cert with some other encoding, the best we can do is the 925289177Speter * fuzzy_escape(). Note: Technically IA5 isn't valid in this 926289177Speter * context, however in the real world it may pop up. */ 927289177Speter default: 928289177Speter return fuzzy_escape(src_string, result_pool); 929289177Speter } 930289177Speter 931289177Speter if (err) 932289177Speter { 933289177Speter svn_error_clear(err); 934289177Speter return fuzzy_escape(src_string, result_pool); 935289177Speter } 936289177Speter 937289177Speter return nul_escape(utf8_string, result_pool); 938289177Speter} 939289177Speter 940289177Speterstatic svn_error_t * 941289177Speterx509_name_to_certinfo(apr_array_header_t **result, 942289177Speter const x509_name *dn, 943289177Speter apr_pool_t *scratch_pool, 944289177Speter apr_pool_t *result_pool) 945289177Speter{ 946289177Speter const x509_name *name = dn; 947289177Speter 948289177Speter *result = apr_array_make(result_pool, 6, sizeof(svn_x509_name_attr_t *)); 949289177Speter 950289177Speter while (name != NULL) { 951289177Speter svn_x509_name_attr_t *attr = apr_palloc(result_pool, sizeof(svn_x509_name_attr_t)); 952289177Speter 953289177Speter attr->oid_len = name->oid.len; 954362181Sdim attr->oid = apr_pmemdup(result_pool, name->oid.p, attr->oid_len); 955289177Speter attr->utf8_value = x509name_to_utf8_string(name, result_pool); 956289177Speter if (!attr->utf8_value) 957289177Speter /* this should never happen */ 958289177Speter attr->utf8_value = apr_pstrdup(result_pool, "??"); 959289177Speter APR_ARRAY_PUSH(*result, const svn_x509_name_attr_t *) = attr; 960289177Speter 961289177Speter name = name->next; 962289177Speter } 963289177Speter 964289177Speter return SVN_NO_ERROR; 965289177Speter} 966289177Speter 967289177Speterstatic svn_boolean_t 968289177Speteris_hostname(const char *str) 969289177Speter{ 970289177Speter apr_size_t i, len = strlen(str); 971289177Speter 972289177Speter for (i = 0; i < len; i++) 973289177Speter { 974289177Speter char c = str[i]; 975289177Speter 976289177Speter /* '-' is only legal when not at the start or end of a label */ 977289177Speter if (c == '-') 978289177Speter { 979289177Speter if (i + 1 != len) 980289177Speter { 981289177Speter if (str[i + 1] == '.') 982289177Speter return FALSE; /* '-' preceeds a '.' */ 983289177Speter } 984289177Speter else 985289177Speter return FALSE; /* '-' is at end of string */ 986289177Speter 987289177Speter /* determine the previous character. */ 988289177Speter if (i == 0) 989289177Speter return FALSE; /* '-' is at start of string */ 990289177Speter else 991289177Speter if (str[i - 1] == '.') 992289177Speter return FALSE; /* '-' follows a '.' */ 993289177Speter } 994289177Speter else if (c != '*' && c != '.' && !svn_ctype_isalnum(c)) 995289177Speter return FALSE; /* some character not allowed */ 996289177Speter } 997289177Speter 998289177Speter return TRUE; 999289177Speter} 1000289177Speter 1001289177Speterstatic const char * 1002289177Speterx509parse_get_cn(apr_array_header_t *subject) 1003289177Speter{ 1004289177Speter int i; 1005289177Speter 1006289177Speter for (i = 0; i < subject->nelts; ++i) 1007289177Speter { 1008289177Speter const svn_x509_name_attr_t *attr = APR_ARRAY_IDX(subject, i, const svn_x509_name_attr_t *); 1009289177Speter if (equal(attr->oid, attr->oid_len, 1010289177Speter SVN_X509_OID_COMMON_NAME, sizeof(SVN_X509_OID_COMMON_NAME) - 1)) 1011289177Speter return attr->utf8_value; 1012289177Speter } 1013289177Speter 1014289177Speter return NULL; 1015289177Speter} 1016289177Speter 1017289177Speter 1018289177Speterstatic void 1019289177Speterx509parse_get_hostnames(svn_x509_certinfo_t *ci, x509_cert *crt, 1020289177Speter apr_pool_t *result_pool, apr_pool_t *scratch_pool) 1021289177Speter{ 1022289177Speter ci->hostnames = NULL; 1023289177Speter 1024289177Speter if (crt->dnsnames->nelts > 0) 1025289177Speter { 1026289177Speter int i; 1027289177Speter 1028289177Speter ci->hostnames = apr_array_make(result_pool, crt->dnsnames->nelts, 1029289177Speter sizeof(const char*)); 1030289177Speter 1031289177Speter /* Subject Alt Names take priority */ 1032289177Speter for (i = 0; i < crt->dnsnames->nelts; i++) 1033289177Speter { 1034289177Speter x509_buf *dnsname = APR_ARRAY_IDX(crt->dnsnames, i, x509_buf *); 1035289177Speter const svn_string_t *temp = svn_string_ncreate((const char *)dnsname->p, 1036289177Speter dnsname->len, 1037289177Speter scratch_pool); 1038289177Speter 1039289177Speter APR_ARRAY_PUSH(ci->hostnames, const char*) 1040289177Speter = fuzzy_escape(temp, result_pool); 1041289177Speter } 1042289177Speter } 1043289177Speter else 1044289177Speter { 1045289177Speter /* no SAN then get the hostname from the CommonName on the cert */ 1046289177Speter const char *utf8_value; 1047289177Speter 1048289177Speter utf8_value = x509parse_get_cn(ci->subject); 1049289177Speter 1050289177Speter if (utf8_value && is_hostname(utf8_value)) 1051289177Speter { 1052289177Speter ci->hostnames = apr_array_make(result_pool, 1, sizeof(const char*)); 1053289177Speter APR_ARRAY_PUSH(ci->hostnames, const char*) = utf8_value; 1054289177Speter } 1055289177Speter } 1056289177Speter} 1057289177Speter 1058289177Speter/* 1059289177Speter * Parse one certificate. 1060289177Speter */ 1061289177Spetersvn_error_t * 1062289177Spetersvn_x509_parse_cert(svn_x509_certinfo_t **certinfo, 1063289177Speter const char *buf, 1064289177Speter apr_size_t buflen, 1065289177Speter apr_pool_t *result_pool, 1066289177Speter apr_pool_t *scratch_pool) 1067289177Speter{ 1068289177Speter svn_error_t *err; 1069289177Speter ptrdiff_t len; 1070289177Speter const unsigned char *p; 1071289177Speter const unsigned char *end; 1072289177Speter x509_cert *crt; 1073289177Speter svn_x509_certinfo_t *ci; 1074289177Speter 1075289177Speter crt = apr_pcalloc(scratch_pool, sizeof(*crt)); 1076289177Speter p = (const unsigned char *)buf; 1077289177Speter len = buflen; 1078289177Speter end = p + len; 1079289177Speter 1080289177Speter /* 1081289177Speter * Certificate ::= SEQUENCE { 1082289177Speter * tbsCertificate TBSCertificate, 1083289177Speter * signatureAlgorithm AlgorithmIdentifier, 1084289177Speter * signatureValue BIT STRING } 1085289177Speter */ 1086289177Speter err = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE); 1087289177Speter if (err) 1088289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_FORMAT, err, NULL); 1089289177Speter 1090289177Speter if (len != (end - p)) 1091289177Speter { 1092289177Speter err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL); 1093289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_FORMAT, err, NULL); 1094289177Speter } 1095289177Speter 1096289177Speter /* 1097289177Speter * TBSCertificate ::= SEQUENCE { 1098289177Speter */ 1099289177Speter err = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE); 1100289177Speter if (err) 1101289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_FORMAT, err, NULL); 1102289177Speter 1103289177Speter end = p + len; 1104289177Speter 1105289177Speter /* 1106289177Speter * Version ::= INTEGER { v1(0), v2(1), v3(2) } 1107289177Speter * 1108289177Speter * CertificateSerialNumber ::= INTEGER 1109289177Speter * 1110289177Speter * signature AlgorithmIdentifier 1111289177Speter */ 1112289177Speter SVN_ERR(x509_get_version(&p, end, &crt->version)); 1113289177Speter SVN_ERR(x509_get_serial(&p, end, &crt->serial)); 1114289177Speter SVN_ERR(x509_get_alg(&p, end, &crt->sig_oid1)); 1115289177Speter 1116289177Speter crt->version++; 1117289177Speter 1118289177Speter if (crt->version > 3) 1119289177Speter return svn_error_create(SVN_ERR_X509_CERT_UNKNOWN_VERSION, NULL, NULL); 1120289177Speter 1121289177Speter /* 1122289177Speter * issuer Name 1123289177Speter */ 1124289177Speter err = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE); 1125289177Speter if (err) 1126289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_FORMAT, err, NULL); 1127289177Speter 1128289177Speter SVN_ERR(x509_get_name(&p, p + len, &crt->issuer, scratch_pool)); 1129289177Speter 1130289177Speter /* 1131289177Speter * Validity ::= SEQUENCE { 1132289177Speter * notBefore Time, 1133289177Speter * notAfter Time } 1134289177Speter * 1135289177Speter */ 1136289177Speter SVN_ERR(x509_get_dates(&crt->valid_from, &crt->valid_to, &p, end, 1137289177Speter scratch_pool)); 1138289177Speter 1139289177Speter /* 1140289177Speter * subject Name 1141289177Speter */ 1142289177Speter err = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE); 1143289177Speter if (err) 1144289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_FORMAT, err, NULL); 1145289177Speter 1146289177Speter SVN_ERR(x509_get_name(&p, p + len, &crt->subject, scratch_pool)); 1147289177Speter 1148289177Speter /* 1149289177Speter * SubjectPublicKeyInfo ::= SEQUENCE 1150289177Speter * algorithm AlgorithmIdentifier, 1151289177Speter * subjectPublicKey BIT STRING } 1152289177Speter */ 1153289177Speter err = asn1_get_tag(&p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE); 1154289177Speter if (err) 1155289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_FORMAT, err, NULL); 1156289177Speter 1157289177Speter /* Skip pubkey. */ 1158289177Speter p += len; 1159289177Speter 1160289177Speter /* 1161289177Speter * issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, 1162289177Speter * -- If present, version shall be v2 or v3 1163289177Speter * subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, 1164289177Speter * -- If present, version shall be v2 or v3 1165289177Speter * extensions [3] EXPLICIT Extensions OPTIONAL 1166289177Speter * -- If present, version shall be v3 1167289177Speter */ 1168289177Speter crt->dnsnames = apr_array_make(scratch_pool, 3, sizeof(x509_buf *)); 1169289177Speter 1170289177Speter /* Try to parse issuerUniqueID, subjectUniqueID and extensions for *every* 1171289177Speter * version (X.509 v1, v2 and v3), not just v2 or v3. If they aren't present, 1172289177Speter * we are fine, but we don't want to throw an error if they are. v1 and v2 1173289177Speter * certificates with the corresponding extra fields are ill-formed per RFC 1174289177Speter * 5280 s. 4.1, but we suspect they could exist in the real world. Other 1175289177Speter * X.509 parsers (e.g., within OpenSSL or Microsoft CryptoAPI) aren't picky 1176289177Speter * about these certificates, and we also allow them. */ 1177289177Speter SVN_ERR(x509_get_uid(&p, end, &crt->issuer_id, 1)); 1178289177Speter SVN_ERR(x509_get_uid(&p, end, &crt->subject_id, 2)); 1179289177Speter SVN_ERR(x509_get_ext(crt->dnsnames, &p, end)); 1180289177Speter 1181289177Speter if (p != end) 1182289177Speter { 1183289177Speter err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL); 1184289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_FORMAT, err, NULL); 1185289177Speter } 1186289177Speter 1187289177Speter end = (const unsigned char*) buf + buflen; 1188289177Speter 1189289177Speter /* 1190289177Speter * signatureAlgorithm AlgorithmIdentifier, 1191289177Speter * signatureValue BIT STRING 1192289177Speter */ 1193289177Speter SVN_ERR(x509_get_alg(&p, end, &crt->sig_oid2)); 1194289177Speter 1195289177Speter if (!oids_equal(&crt->sig_oid1, &crt->sig_oid2)) 1196289177Speter return svn_error_create(SVN_ERR_X509_CERT_SIG_MISMATCH, NULL, NULL); 1197289177Speter 1198289177Speter SVN_ERR(x509_get_sig(&p, end, &crt->sig)); 1199289177Speter 1200289177Speter if (p != end) 1201289177Speter { 1202289177Speter err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL); 1203289177Speter return svn_error_create(SVN_ERR_X509_CERT_INVALID_FORMAT, err, NULL); 1204289177Speter } 1205289177Speter 1206289177Speter ci = apr_pcalloc(result_pool, sizeof(*ci)); 1207289177Speter 1208289177Speter /* Get the subject name */ 1209289177Speter SVN_ERR(x509_name_to_certinfo(&ci->subject, &crt->subject, 1210289177Speter scratch_pool, result_pool)); 1211289177Speter 1212289177Speter /* Get the issuer name */ 1213289177Speter SVN_ERR(x509_name_to_certinfo(&ci->issuer, &crt->issuer, 1214289177Speter scratch_pool, result_pool)); 1215289177Speter 1216289177Speter /* Copy the validity range */ 1217289177Speter ci->valid_from = crt->valid_from; 1218289177Speter ci->valid_to = crt->valid_to; 1219289177Speter 1220289177Speter /* Calculate the SHA1 digest of the certificate, otherwise known as 1221289177Speter the fingerprint */ 1222289177Speter SVN_ERR(svn_checksum(&ci->digest, svn_checksum_sha1, buf, buflen, 1223289177Speter result_pool)); 1224289177Speter 1225289177Speter /* Construct the array of host names */ 1226289177Speter x509parse_get_hostnames(ci, crt, result_pool, scratch_pool); 1227289177Speter 1228289177Speter *certinfo = ci; 1229289177Speter return SVN_NO_ERROR; 1230289177Speter} 1231289177Speter 1232