x509info.c revision 362181
1189251Ssam/* 2189251Ssam * x509info.c: Accessors for svn_x509_certinfo_t 3346981Scy * 4189251Ssam * ==================================================================== 5252726Srpaulo * Licensed to the Apache Software Foundation (ASF) under one 6252726Srpaulo * or more contributor license agreements. See the NOTICE file 7189251Ssam * distributed with this work for additional information 8189251Ssam * regarding copyright ownership. The ASF licenses this file 9189251Ssam * to you under the Apache License, Version 2.0 (the 10189251Ssam * "License"); you may not use this file except in compliance 11189251Ssam * with the License. You may obtain a copy of the License at 12214734Srpaulo * 13214734Srpaulo * http://www.apache.org/licenses/LICENSE-2.0 14214734Srpaulo * 15281806Srpaulo * Unless required by applicable law or agreed to in writing, 16346981Scy * software distributed under the License is distributed on an 17214734Srpaulo * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 18214734Srpaulo * KIND, either express or implied. See the License for the 19189251Ssam * specific language governing permissions and limitations 20189251Ssam * under the License. 21189251Ssam * ==================================================================== 22189251Ssam */ 23189251Ssam 24346981Scy 25281806Srpaulo 26346981Scy#include <string.h> 27346981Scy 28346981Scy#include <apr_pools.h> 29281806Srpaulo#include <apr_tables.h> 30346981Scy 31346981Scy#include "svn_string.h" 32346981Scy#include "svn_hash.h" 33346981Scy#include "x509.h" 34346981Scy 35346981Scy 36346981Scy 37346981Scysvn_x509_name_attr_t * 38346981Scysvn_x509_name_attr_dup(const svn_x509_name_attr_t *attr, 39346981Scy apr_pool_t *result_pool, 40346981Scy apr_pool_t *scratch_pool) 41346981Scy{ 42281806Srpaulo svn_x509_name_attr_t *result = apr_palloc(result_pool, sizeof(*result)); 43281806Srpaulo result->oid_len = attr->oid_len; 44281806Srpaulo result->oid = apr_pmemdup(result_pool, attr->oid, attr->oid_len); 45346981Scy result->utf8_value = apr_pstrdup(result_pool, attr->utf8_value); 46346981Scy 47281806Srpaulo return result; 48346981Scy} 49346981Scy 50346981Scyconst unsigned char * 51346981Scysvn_x509_name_attr_get_oid(const svn_x509_name_attr_t *attr, apr_size_t *len) 52346981Scy{ 53346981Scy *len = attr->oid_len; 54346981Scy return attr->oid; 55346981Scy} 56346981Scy 57346981Scyconst char * 58346981Scysvn_x509_name_attr_get_value(const svn_x509_name_attr_t *attr) 59346981Scy{ 60346981Scy return attr->utf8_value; 61346981Scy} 62346981Scy 63346981Scy/* Array elements are assumed to be nul-terminated C strings. */ 64346981Scystatic apr_array_header_t * 65346981Scydeep_copy_array(apr_array_header_t *s, apr_pool_t *result_pool) 66346981Scy{ 67346981Scy int i; 68346981Scy apr_array_header_t *d; 69346981Scy 70281806Srpaulo if (!s) 71346981Scy return NULL; 72346981Scy 73346981Scy d = apr_array_copy(result_pool, s); 74346981Scy 75346981Scy /* Make a deep copy of the strings in the array. */ 76346981Scy for (i = 0; i < s->nelts; ++i) 77346981Scy { 78281806Srpaulo APR_ARRAY_IDX(d, i, const char *) = 79281806Srpaulo apr_pstrdup(result_pool, APR_ARRAY_IDX(s, i, const char *)); 80281806Srpaulo } 81346981Scy 82346981Scy return d; 83281806Srpaulo} 84346981Scy 85346981Scy/* Copy an array with elements that are svn_x509_name_attr_t's */ 86346981Scystatic apr_array_header_t * 87346981Scydeep_copy_name_attrs(apr_array_header_t *s, apr_pool_t *result_pool) 88346981Scy{ 89346981Scy int i; 90346981Scy apr_array_header_t *d; 91346981Scy 92346981Scy if (!s) 93346981Scy return NULL; 94346981Scy 95346981Scy d = apr_array_copy(result_pool, s); 96346981Scy 97346981Scy /* Make a deep copy of the svn_x509_name_attr_t's in the array. */ 98346981Scy for (i = 0; i < s->nelts; ++i) 99346981Scy { 100346981Scy APR_ARRAY_IDX(d, i, const svn_x509_name_attr_t *) = 101281806Srpaulo svn_x509_name_attr_dup(APR_ARRAY_IDX(s, i, svn_x509_name_attr_t *), 102346981Scy result_pool, result_pool); 103346981Scy } 104346981Scy 105346981Scy return d; 106346981Scy} 107346981Scy 108346981Scysvn_x509_certinfo_t * 109346981Scysvn_x509_certinfo_dup(const svn_x509_certinfo_t *certinfo, 110346981Scy apr_pool_t *result_pool, 111346981Scy apr_pool_t *scratch_pool) 112346981Scy{ 113346981Scy svn_x509_certinfo_t *result = apr_palloc(result_pool, sizeof(*result)); 114281806Srpaulo result->subject = deep_copy_name_attrs(certinfo->subject, result_pool); 115281806Srpaulo result->issuer = deep_copy_name_attrs(certinfo->issuer, result_pool); 116281806Srpaulo result->valid_from = certinfo->valid_from; 117189251Ssam result->valid_to = certinfo->valid_to; 118346981Scy result->digest = svn_checksum_dup(certinfo->digest, result_pool); 119346981Scy result->hostnames = deep_copy_array(certinfo->hostnames, result_pool); 120346981Scy 121346981Scy return result; 122346981Scy} 123346981Scy 124346981Scytypedef struct asn1_oid { 125346981Scy const unsigned char *oid; 126346981Scy const apr_size_t oid_len; 127346981Scy const char *short_label; 128346981Scy const char *long_label; 129346981Scy} asn1_oid; 130346981Scy 131346981Scy#define CONSTANT_PAIR(c) (const unsigned char *)(c), sizeof((c)) - 1 132346981Scy 133346981Scystatic const asn1_oid asn1_oids[] = { 134346981Scy { CONSTANT_PAIR(SVN_X509_OID_COMMON_NAME), "CN", "commonName" }, 135346981Scy { CONSTANT_PAIR(SVN_X509_OID_COUNTRY), "C", "countryName" }, 136346981Scy { CONSTANT_PAIR(SVN_X509_OID_LOCALITY), "L", "localityName" }, 137346981Scy { CONSTANT_PAIR(SVN_X509_OID_STATE), "ST", "stateOrProvinceName" }, 138346981Scy { CONSTANT_PAIR(SVN_X509_OID_ORGANIZATION), "O", "organizationName" }, 139346981Scy { CONSTANT_PAIR(SVN_X509_OID_ORG_UNIT), "OU", "organizationalUnitName"}, 140346981Scy { CONSTANT_PAIR(SVN_X509_OID_EMAIL), NULL, "emailAddress" }, 141346981Scy { NULL }, 142346981Scy}; 143346981Scy 144346981Scy/* Given an OID return a null-terminated C string representation. 145346981Scy * For example an OID with the bytes "\x2A\x86\x48\x86\xF7\x0D\x01\x09\x01" 146346981Scy * would be converted to the string "1.2.840.113549.1.9.1". */ 147346981Scyconst char * 148346981Scysvn_x509_oid_to_string(const unsigned char *oid, apr_size_t oid_len, 149346981Scy apr_pool_t *scratch_pool, apr_pool_t *result_pool) 150346981Scy{ 151346981Scy svn_stringbuf_t *out = svn_stringbuf_create_empty(result_pool); 152346981Scy const unsigned char *p = oid; 153346981Scy const unsigned char *end = p + oid_len; 154346981Scy const char *temp; 155346981Scy 156346981Scy while (p != end) { 157346981Scy if (p == oid) 158346981Scy { 159346981Scy /* Handle decoding the first two values of the OID. These values 160346981Scy * are encoded by taking the first value and adding 40 to it and 161346981Scy * adding the result to the second value, then placing this single 162346981Scy * value in the first byte of the output. This is unambiguous since 163346981Scy * the first value is apparently limited to 0, 1 or 2 and the second 164346981Scy * is limited to 0 to 39. */ 165346981Scy temp = apr_psprintf(scratch_pool, "%d.%d", *p / 40, *p % 40); 166346981Scy p++; 167346981Scy } 168346981Scy else if (*p < 128) 169346981Scy { 170346981Scy /* The remaining values if they're less than 128 are just 171346981Scy * the number one to one encoded */ 172346981Scy temp = apr_psprintf(scratch_pool, ".%d", *p); 173189251Ssam p++; 174189251Ssam } 175281806Srpaulo else 176281806Srpaulo { 177189251Ssam /* Values greater than 128 are encoded as a series of 7 bit values 178189251Ssam * with the left most bit set to indicate this encoding with the 179189251Ssam * last octet missing the left most bit to finish out the series.. */ 180189251Ssam unsigned int collector = 0; 181189251Ssam svn_boolean_t dot = FALSE; 182189251Ssam 183189251Ssam do { 184189251Ssam if (collector == 0 && *p == 0x80) 185189251Ssam { 186189251Ssam /* include leading zeros in the string representation 187189251Ssam technically not legal, but this seems nicer than just 188189251Ssam returning NULL */ 189189251Ssam if (!dot) 190189251Ssam { 191189251Ssam svn_stringbuf_appendbyte(out, '.'); 192281806Srpaulo dot = TRUE; 193281806Srpaulo } 194189251Ssam svn_stringbuf_appendbyte(out, '0'); 195346981Scy } 196189251Ssam else if (collector > UINT_MAX >> 7) 197346981Scy { 198346981Scy /* overflow */ 199346981Scy return NULL; 200346981Scy } 201346981Scy collector = collector << 7 | (*(p++) & 0x7f); 202346981Scy } while (p != end && *p > 127); 203189251Ssam if (collector > UINT_MAX >> 7) 204252726Srpaulo return NULL; /* overflow */ 205189251Ssam collector = collector << 7 | *(p++); 206346981Scy temp = apr_psprintf(scratch_pool, "%s%d", dot ? "" : ".", collector); 207281806Srpaulo } 208252726Srpaulo svn_stringbuf_appendcstr(out, temp); 209189251Ssam } 210346981Scy 211281806Srpaulo if (svn_stringbuf_isempty(out)) 212214734Srpaulo return NULL; 213189251Ssam 214189251Ssam return out->data; 215209158Srpaulo} 216189251Ssam 217346981Scystatic const asn1_oid *oid_to_asn1_oid(unsigned char *oid, apr_size_t oid_len) 218189251Ssam{ 219209158Srpaulo const asn1_oid *entry; 220281806Srpaulo 221281806Srpaulo for (entry = asn1_oids; entry->oid; entry++) 222346981Scy { 223346981Scy if (oid_len == entry->oid_len && 224346981Scy memcmp(oid, entry->oid, oid_len) == 0) 225346981Scy return entry; 226346981Scy } 227346981Scy 228346981Scy return NULL; 229281806Srpaulo} 230281806Srpaulo 231346981Scystatic const char *oid_to_best_label(unsigned char *oid, apr_size_t oid_len, 232346981Scy apr_pool_t *result_pool) 233281806Srpaulo{ 234281806Srpaulo const asn1_oid *entry = oid_to_asn1_oid(oid, oid_len); 235281806Srpaulo 236281806Srpaulo if (entry) 237346981Scy { 238346981Scy if (entry->short_label) 239281806Srpaulo return entry->short_label; 240281806Srpaulo 241281806Srpaulo if (entry->long_label) 242281806Srpaulo return entry->long_label; 243281806Srpaulo } 244281806Srpaulo else 245281806Srpaulo { 246346981Scy const char *oid_string = svn_x509_oid_to_string(oid, oid_len, 247346981Scy result_pool, result_pool); 248281806Srpaulo if (oid_string) 249281806Srpaulo return oid_string; 250281806Srpaulo } 251281806Srpaulo 252281806Srpaulo return "??"; 253346981Scy} 254346981Scy 255346981Scy/* 256346981Scy * Store the name from dn in printable form into buf, 257346981Scy * using scratch_pool for any temporary allocations. 258346981Scy * If CN is not NULL, return any common name in CN 259346981Scy */ 260346981Scystatic const char * 261346981Scyget_dn(apr_array_header_t *name, 262346981Scy apr_pool_t *result_pool) 263346981Scy{ 264346981Scy svn_stringbuf_t *buf = svn_stringbuf_create_empty(result_pool); 265346981Scy int n; 266346981Scy 267346981Scy for (n = 0; n < name->nelts; n++) 268346981Scy { 269346981Scy const svn_x509_name_attr_t *attr = APR_ARRAY_IDX(name, n, svn_x509_name_attr_t *); 270346981Scy 271346981Scy if (n > 0) 272346981Scy svn_stringbuf_appendcstr(buf, ", "); 273346981Scy 274346981Scy svn_stringbuf_appendcstr(buf, oid_to_best_label(attr->oid, attr->oid_len, result_pool)); 275346981Scy svn_stringbuf_appendbyte(buf, '='); 276346981Scy svn_stringbuf_appendcstr(buf, attr->utf8_value); 277346981Scy } 278346981Scy 279346981Scy return buf->data; 280346981Scy} 281346981Scy 282346981Scyconst char * 283346981Scysvn_x509_certinfo_get_subject(const svn_x509_certinfo_t *certinfo, 284346981Scy apr_pool_t *result_pool) 285346981Scy{ 286346981Scy return get_dn(certinfo->subject, result_pool); 287346981Scy} 288346981Scy 289346981Scyconst apr_array_header_t * 290346981Scysvn_x509_certinfo_get_subject_attrs(const svn_x509_certinfo_t *certinfo) 291346981Scy{ 292346981Scy return certinfo->subject; 293346981Scy} 294346981Scy 295346981Scyconst char * 296346981Scysvn_x509_certinfo_get_issuer(const svn_x509_certinfo_t *certinfo, 297346981Scy apr_pool_t *result_pool) 298346981Scy{ 299346981Scy return get_dn(certinfo->issuer, result_pool); 300346981Scy} 301346981Scy 302346981Scyconst apr_array_header_t * 303346981Scysvn_x509_certinfo_get_issuer_attrs(const svn_x509_certinfo_t *certinfo) 304346981Scy{ 305346981Scy return certinfo->issuer; 306346981Scy} 307346981Scy 308281806Srpauloapr_time_t 309346981Scysvn_x509_certinfo_get_valid_from(const svn_x509_certinfo_t *certinfo) 310346981Scy{ 311346981Scy return certinfo->valid_from; 312281806Srpaulo} 313281806Srpaulo 314281806Srpauloapr_time_t 315189251Ssamsvn_x509_certinfo_get_valid_to(const svn_x509_certinfo_t *certinfo) 316346981Scy{ 317346981Scy return certinfo->valid_to; 318346981Scy} 319189251Ssam 320189251Ssamconst svn_checksum_t * 321189251Ssamsvn_x509_certinfo_get_digest(const svn_x509_certinfo_t *certinfo) 322189251Ssam{ 323189251Ssam return certinfo->digest; 324189251Ssam} 325189251Ssam 326189251Ssamconst apr_array_header_t * 327189251Ssamsvn_x509_certinfo_get_hostnames(const svn_x509_certinfo_t *certinfo) 328189251Ssam{ 329189251Ssam return certinfo->hostnames; 330189251Ssam} 331189251Ssam 332189251Ssam