You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2014/06/18 18:25:07 UTC

svn commit: r1603509 - in /subversion/branches/svn-auth-x509: ./ subversion/libsvn_subr/x509.h subversion/libsvn_subr/x509parse.c

Author: stsp
Date: Wed Jun 18 16:25:07 2014
New Revision: 1603509

URL: http://svn.apache.org/r1603509
Log:
New branch with the prupose of adding a native x509 parser to 'svn auth'.

* subversion/libsvn_subr/x509.h, 
  subversion/libsvn_subr/x509parse.c: New files.
   Starting point for a minimal x509 parser.
   Based on code from tropicssl
   commit 92bb3462dfbdb4568c92be19e8904129a17b1eed
   https://git.gitorious.org/tropicssl/tropicssl.git

Added:
    subversion/branches/svn-auth-x509/   (props changed)
      - copied from r1603508, subversion/trunk/
    subversion/branches/svn-auth-x509/subversion/libsvn_subr/x509.h
    subversion/branches/svn-auth-x509/subversion/libsvn_subr/x509parse.c

Propchange: subversion/branches/svn-auth-x509/
------------------------------------------------------------------------------
--- bugtraq:logregex (added)
+++ bugtraq:logregex Wed Jun 18 16:25:07 2014
@@ -0,0 +1,2 @@
+[Ii]ssues?:?(\s*(,|and)?\s*#\d+)+
+(\d+)

Propchange: subversion/branches/svn-auth-x509/
------------------------------------------------------------------------------
    bugtraq:url = http://subversion.tigris.org/issues/show_bug.cgi?id=%BUGID%

Propchange: subversion/branches/svn-auth-x509/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Wed Jun 18 16:25:07 2014
@@ -0,0 +1,57 @@
+ChangeLog*
+Makefile
+config.cache
+config.log
+config.nice
+config.status
+configure
+libtool
+.gdb_history
+.swig_checked
+*.orig
+*.rej
+TAGS
+tags
+neon
+build-outputs.mk
+autogen-standalone.mk
+autom4te.cache
+gen-make.opts
+tests.log*
+fails.log*
+db4-win32
+db
+*.o
+*~
+.*~
+apr
+apr-util
+apr-iconv
+Release
+Debug
+ipch
+subversion_msvc.dsw
+subversion_msvc.ncb
+subversion_msvc.opt
+subversion_msvc.plg
+subversion_vcnet.sln
+subversion_vcnet.ncb
+subversion_vcnet.suo
+subversion_vcnet.v11.suo
+subversion_vcnet.sdf
+subversion_vcnet.opensdf
+mkmf.log
+.project
+.classpath
+.cdtproject
+.settings
+.cproject
+zlib
+sqlite-amalgamation
+serf
+gmock-fused
+.git
+.gitignore
+compile_commands.json
+.kdev4
+*.kdev4

Propchange: subversion/branches/svn-auth-x509/
------------------------------------------------------------------------------
--- svn:mergeinfo (added)
+++ svn:mergeinfo Wed Jun 18 16:25:07 2014
@@ -0,0 +1,83 @@
+/subversion/branches/1.5.x-r30215:870312
+/subversion/branches/1.7.x-fs-verify:1146708,1161180
+/subversion/branches/10Gb:1388102,1388163-1388190,1388195,1388202,1388205,1388211,1388276,1388362,1388375,1388394,1388636,1388639-1388640,1388643-1388644,1388654,1388720,1388789,1388795,1388801,1388805,1388807,1388810,1388816,1389044,1389276,1389289,1389662,1389867,1390017,1390209,1390216,1390407,1390409,1390414,1390419,1390955
+/subversion/branches/atomic-revprop:965046-1000689
+/subversion/branches/auto-props-sdc:1384106-1401643
+/subversion/branches/bdb-reverse-deltas:872050-872529
+/subversion/branches/cache-server:1458643-1476567
+/subversion/branches/diff-callbacks3:870059-870761
+/subversion/branches/diff-optimizations:1031270-1037352
+/subversion/branches/diff-optimizations-bytes:1037353-1067789
+/subversion/branches/dont-save-plaintext-passwords-by-default:870728-871118
+/subversion/branches/double-delete:870511-872970
+/subversion/branches/ev2-export:1325914,1332738,1413107
+/subversion/branches/explore-wc:875486,875493,875497,875507,875511,875514,875559,875580-875581,875584,875587,875611,875627,875647,875667-875668,875711-875712,875733-875734,875736,875744-875748,875751,875758,875782,875795-875796,875830,875836,875838,875842,875852,875855,875864,875870,875873,875880,875885-875888,875890,875897-875898,875905,875907-875909,875935,875943-875944,875946,875979,875982-875983,875985-875986,875990,875997
+/subversion/branches/file-externals:871779-873302
+/subversion/branches/fs-rep-sharing:869036-873803
+/subversion/branches/fsfs-format7:1426304,1430673,1433848,1438408,1438982,1441129,1442051,1442068,1442504,1442910,1443171,1443803,1444690,1444693,1444695,1445040,1445080,1446103,1451129,1453590,1454307,1460579,1461851,1461865,1462837,1462904,1463120,1467362,1467382,1469487,1471208,1477166,1478055,1481447,1489817,1489949,1490673-1490674,1491784,1493042,1498029,1498103,1498155,1500054,1507729-1507731,1507735-1507736
+/subversion/branches/fsfs-improvements:1499981-1547039
+/subversion/branches/fsfs-lock-many:1571740-1577217
+/subversion/branches/fsfs-pack:873717-874575
+/subversion/branches/fsx:1507845-1509914
+/subversion/branches/gnome-keyring:870558-871410
+/subversion/branches/gpg-agent-password-store:1005036-1150766
+/subversion/branches/gtest_addition:1452117-1502138
+/subversion/branches/http-protocol-v2:874395-876041
+/subversion/branches/in-memory-cache:869829-871452
+/subversion/branches/in-repo-authz:1414342-1424779
+/subversion/branches/inheritable-props:1297080-1395089
+/subversion/branches/integrate-cache-item-serialization:1068724-1068739
+/subversion/branches/integrate-cache-membuffer:998649-998852
+/subversion/branches/integrate-compression-level:1068651-1072287
+/subversion/branches/integrate-io-improvements:1068684-1072297
+/subversion/branches/integrate-is-cachable:1072568-1074082
+/subversion/branches/integrate-partial-getter:1072558-1076552
+/subversion/branches/integrate-readline-speedup:1072553-1072555
+/subversion/branches/integrate-stream-api-extensions:1068695-1072516
+/subversion/branches/integrate-string-improvements:1068251-1190617
+/subversion/branches/integrate-txdelta-caching:1072541-1078213
+/subversion/branches/issue-2779-dev:965496-984198
+/subversion/branches/issue-2843-dev:871432-874179
+/subversion/branches/issue-3000:871713,871716-871719,871721-871726,871728,871734
+/subversion/branches/issue-3067-deleted-subtrees:873375-874084
+/subversion/branches/issue-3148-dev:875193-875204
+/subversion/branches/issue-3220-dev:872210-872226
+/subversion/branches/issue-3242-dev:879653-896436
+/subversion/branches/issue-3334-dirs:875156-875867
+/subversion/branches/issue-3975:1152931-1160746
+/subversion/branches/issue-4116-dev:1424719-1425040
+/subversion/branches/issue-4194-dev:1410507-1414880
+/subversion/branches/javahl-ra:991978-1494640
+/subversion/branches/kwallet:870785-871314
+/subversion/branches/log-addressing:1509279-1546844
+/subversion/branches/log-g-performance:870941-871032
+/subversion/branches/merge-skips-obstructions:874525-874615
+/subversion/branches/multi-layer-moves:1239019-1300930
+/subversion/branches/nfc-nfd-aware-client:870276,870376
+/subversion/branches/node_pool:1304828-1305388
+/subversion/branches/performance:979193,980118,981087,981090,981189,981194,981287,981684,981827,982043,982355,983398,983406,983430,983474,983488,983490,983760,983764,983766,983770,984927,984973,984984,985014,985037,985046,985472,985477,985482,985487-985488,985493,985497,985500,985514,985601,985603,985606,985669,985673,985695,985697,986453,986465,986485,986491-986492,986517,986521,986605,986608,986817,986832,987865,987868-987869,987872,987886-987888,987893,988319,988898,990330,990533,990535-990537,990541,990568,990572,990574-990575,990600,990759,992899,992904,992911,993127,993141,994956,995478,995507,995603,998012,998858,999098,1001413,1001417,1004291,1022668,1022670,1022676,1022715,1022719,1025660,1025672,1027193,1027203,1027206,1027214,1027227,1028077,1028092,1028094,1028104,1028107,1028111,1028354,1029038,1029042-1029043,1029054-1029055,1029062-1029063,1029078,1029080,1029090,1029092-1029093,1029111,1029151,1029158,1029229-1029230,1029232,1029335-1029336,1029339-1029340,1029342,10
 29344,1030763,1030827,1031203,1031235,1032285,1032333,1033040,1033057,1033294,1035869,1035882,1039511,1043705,1053735,1056015,1066452,1067683,1067697-1078365
+/subversion/branches/py-tests-as-modules:956579-1033052
+/subversion/branches/ra_serf-digest-authn:875693-876404
+/subversion/branches/reintegrate-improvements:873853-874164
+/subversion/branches/remote-only-status:1581845-1586090
+/subversion/branches/revprop-cache:1298521-1326293
+/subversion/branches/revprop-packing:1143907,1143971,1143997,1144017,1144499,1144568,1146145
+/subversion/branches/subtree-mergeinfo:876734-878766
+/subversion/branches/svn-mergeinfo-enhancements:870119-870195,870197-870288
+/subversion/branches/svn-patch-improvements:918519-934609
+/subversion/branches/svn_mutex:1141683-1182099
+/subversion/branches/svnpatch-diff:865738-876477
+/subversion/branches/svnraisetc:874709-875149
+/subversion/branches/svnserve-logging:869828-870893
+/subversion/branches/tc-issue-3334:874697-874773
+/subversion/branches/tc-merge-notify:874017-874062
+/subversion/branches/tc-resolve:874191-874239
+/subversion/branches/tc_url_rev:874351-874483
+/subversion/branches/tree-conflicts:868291-873154
+/subversion/branches/tree-conflicts-notify:873926-874008
+/subversion/branches/tristate-chunked-request:1502394-1502681
+/subversion/branches/tweak-build-take-two:1424288-1425049,1425051-1425613
+/subversion/branches/uris-as-urls:1060426-1064427
+/subversion/branches/verify-at-commit:1462039-1462408
+/subversion/branches/verify-keep-going:1439280-1546110
+/subversion/branches/wc-collate-path:1402685-1480384

Propchange: subversion/branches/svn-auth-x509/
------------------------------------------------------------------------------
    tsvn:logwidthmarker = 78

Added: subversion/branches/svn-auth-x509/subversion/libsvn_subr/x509.h
URL: http://svn.apache.org/viewvc/subversion/branches/svn-auth-x509/subversion/libsvn_subr/x509.h?rev=1603509&view=auto
==============================================================================
--- subversion/branches/svn-auth-x509/subversion/libsvn_subr/x509.h (added)
+++ subversion/branches/svn-auth-x509/subversion/libsvn_subr/x509.h Wed Jun 18 16:25:07 2014
@@ -0,0 +1,197 @@
+/**
+ * \file x509.h
+ *
+ *  Based on XySSL: Copyright (C) 2006-2008  Christophe Devine
+ *
+ *  Copyright (C) 2009  Paul Bakker <polarssl_maintainer at polarssl dot org>
+ *
+ *  All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *    * Neither the names of PolarSSL or XySSL nor the names of its contributors
+ *      may be used to endorse or promote products derived from this software
+ *      without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ *  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef TROPICSSL_X509_H
+#define TROPICSSL_X509_H
+
+#define TROPICSSL_ERR_ASN1_OUT_OF_DATA                      -0x0014
+#define TROPICSSL_ERR_ASN1_UNEXPECTED_TAG                   -0x0016
+#define TROPICSSL_ERR_ASN1_INVALID_LENGTH                   -0x0018
+#define TROPICSSL_ERR_ASN1_LENGTH_MISMATCH                  -0x001A
+#define TROPICSSL_ERR_ASN1_INVALID_DATA                     -0x001C
+
+#define TROPICSSL_ERR_X509_FEATURE_UNAVAILABLE              -0x0020
+#define TROPICSSL_ERR_X509_CERT_INVALID_PEM                 -0x0040
+#define TROPICSSL_ERR_X509_CERT_INVALID_FORMAT              -0x0060
+#define TROPICSSL_ERR_X509_CERT_INVALID_VERSION             -0x0080
+#define TROPICSSL_ERR_X509_CERT_INVALID_SERIAL              -0x00A0
+#define TROPICSSL_ERR_X509_CERT_INVALID_ALG                 -0x00C0
+#define TROPICSSL_ERR_X509_CERT_INVALID_NAME                -0x00E0
+#define TROPICSSL_ERR_X509_CERT_INVALID_DATE                -0x0100
+#define TROPICSSL_ERR_X509_CERT_INVALID_PUBKEY              -0x0120
+#define TROPICSSL_ERR_X509_CERT_INVALID_SIGNATURE           -0x0140
+#define TROPICSSL_ERR_X509_CERT_INVALID_EXTENSIONS          -0x0160
+#define TROPICSSL_ERR_X509_CERT_UNKNOWN_VERSION             -0x0180
+#define TROPICSSL_ERR_X509_CERT_UNKNOWN_SIG_ALG             -0x01A0
+#define TROPICSSL_ERR_X509_CERT_UNKNOWN_PK_ALG              -0x01C0
+#define TROPICSSL_ERR_X509_CERT_SIG_MISMATCH                -0x01E0
+#define TROPICSSL_ERR_X509_CERT_VERIFY_FAILED               -0x0200
+#define TROPICSSL_ERR_X509_KEY_INVALID_PEM                  -0x0220
+#define TROPICSSL_ERR_X509_KEY_INVALID_VERSION              -0x0240
+#define TROPICSSL_ERR_X509_KEY_INVALID_FORMAT               -0x0260
+#define TROPICSSL_ERR_X509_KEY_INVALID_ENC_IV               -0x0280
+#define TROPICSSL_ERR_X509_KEY_UNKNOWN_ENC_ALG              -0x02A0
+#define TROPICSSL_ERR_X509_KEY_PASSWORD_REQUIRED            -0x02C0
+#define TROPICSSL_ERR_X509_KEY_PASSWORD_MISMATCH            -0x02E0
+#define TROPICSSL_ERR_X509_POINT_ERROR                      -0x0300
+#define TROPICSSL_ERR_X509_VALUE_TO_LENGTH                  -0x0320
+
+#define BADCERT_EXPIRED                 1
+#define BADCERT_REVOKED                 2
+#define BADCERT_CN_MISMATCH             4
+#define BADCERT_NOT_TRUSTED             8
+
+/*
+ * DER constants
+ */
+#define ASN1_BOOLEAN                 0x01
+#define ASN1_INTEGER                 0x02
+#define ASN1_BIT_STRING              0x03
+#define ASN1_OCTET_STRING            0x04
+#define ASN1_NULL                    0x05
+#define ASN1_OID                     0x06
+#define ASN1_UTF8_STRING             0x0C
+#define ASN1_SEQUENCE                0x10
+#define ASN1_SET                     0x11
+#define ASN1_PRINTABLE_STRING        0x13
+#define ASN1_T61_STRING              0x14
+#define ASN1_IA5_STRING              0x16
+#define ASN1_UTC_TIME                0x17
+#define ASN1_UNIVERSAL_STRING        0x1C
+#define ASN1_BMP_STRING              0x1E
+#define ASN1_PRIMITIVE               0x00
+#define ASN1_CONSTRUCTED             0x20
+#define ASN1_CONTEXT_SPECIFIC        0x80
+
+/*
+ * various object identifiers
+ */
+#define X520_COMMON_NAME                3
+#define X520_COUNTRY                    6
+#define X520_LOCALITY                   7
+#define X520_STATE                      8
+#define X520_ORGANIZATION              10
+#define X520_ORG_UNIT                  11
+#define PKCS9_EMAIL                     1
+
+#define X509_OUTPUT_DER              0x01
+#define X509_OUTPUT_PEM              0x02
+#define PEM_LINE_LENGTH                72
+#define X509_ISSUER                  0x01
+#define X509_SUBJECT                 0x02
+
+#define OID_X520                "\x55\x04"
+#define OID_CN                  "\x55\x04\x03"
+#define OID_PKCS1               "\x2A\x86\x48\x86\xF7\x0D\x01\x01"
+#define OID_PKCS1_RSA           "\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01"
+#define OID_PKCS1_RSA_SHA       "\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05"
+#define OID_PKCS9               "\x2A\x86\x48\x86\xF7\x0D\x01\x09"
+#define OID_PKCS9_EMAIL         "\x2A\x86\x48\x86\xF7\x0D\x01\x09\x01"
+
+/*
+ * Structures for parsing X.509 certificates
+ */
+typedef struct _x509_buf {
+	int tag;
+	int len;
+	unsigned char *p;
+} x509_buf;
+
+typedef struct _x509_name {
+	x509_buf oid;
+	x509_buf val;
+	struct _x509_name *next;
+} x509_name;
+
+typedef struct _x509_time {
+	int year, mon, day;
+	int hour, min, sec;
+} x509_time;
+
+typedef struct _x509_cert {
+	x509_buf raw;
+	x509_buf tbs;
+
+	int version;
+	x509_buf serial;
+	x509_buf sig_oid1;
+
+	x509_buf issuer_raw;
+	x509_buf subject_raw;
+
+	x509_name issuer;
+	x509_name subject;
+
+	x509_time valid_from;
+	x509_time valid_to;
+
+	x509_buf pk_oid;
+
+	x509_buf issuer_id;
+	x509_buf subject_id;
+	x509_buf v3_ext;
+
+	int ca_istrue;
+	int max_pathlen;
+
+	x509_buf sig_oid2;
+	x509_buf sig;
+
+} x509_cert;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+	/**
+	 * \brief          Parse one or more certificates and add them
+	 *                 to the chained list
+	 *
+	 * \param chain    points to the start of the chain
+	 * \param buf      buffer holding the certificate data
+	 * \param buflen   size of the buffer
+	 *
+	 * \return         0 if successful, or a specific X509 error code
+	 */
+	int x509parse_crt(x509_cert * chain, const unsigned char *buf, int buflen);
+
+	/**
+	 * \brief          Unallocate all certificate data
+	 */
+	void x509_free(x509_cert * crt);
+
+#ifdef __cplusplus
+}
+#endif
+#endif				/* x509.h */

Added: subversion/branches/svn-auth-x509/subversion/libsvn_subr/x509parse.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-auth-x509/subversion/libsvn_subr/x509parse.c?rev=1603509&view=auto
==============================================================================
--- subversion/branches/svn-auth-x509/subversion/libsvn_subr/x509parse.c (added)
+++ subversion/branches/svn-auth-x509/subversion/libsvn_subr/x509parse.c Wed Jun 18 16:25:07 2014
@@ -0,0 +1,681 @@
+/*
+ *	X.509 certificate and private key decoding
+ *
+ *	Based on XySSL: Copyright (C) 2006-2008	 Christophe Devine
+ *
+ *	Copyright (C) 2009	Paul Bakker <polarssl_maintainer at polarssl dot org>
+ *
+ *	All rights reserved.
+ *
+ *	Redistribution and use in source and binary forms, with or without
+ *	modification, are permitted provided that the following conditions
+ *	are met:
+ *
+ *	  * Redistributions of source code must retain the above copyright
+ *		notice, this list of conditions and the following disclaimer.
+ *	  * Redistributions in binary form must reproduce the above copyright
+ *		notice, this list of conditions and the following disclaimer in the
+ *		documentation and/or other materials provided with the distribution.
+ *	  * Neither the names of PolarSSL or XySSL nor the names of its contributors
+ *		may be used to endorse or promote products derived from this software
+ *		without specific prior written permission.
+ *
+ *	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *	"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *	LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ *	FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *	OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *	SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ *	TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ *	PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *	LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *	NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *	SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ *	The ITU-T X.509 standard defines a certificat format for PKI.
+ *
+ *	http://www.ietf.org/rfc/rfc2459.txt
+ *	http://www.ietf.org/rfc/rfc3279.txt
+ *
+ *	ftp://ftp.rsasecurity.com/pub/pkcs/ascii/pkcs-1v2.asc
+ *
+ *	http://www.itu.int/ITU-T/studygroups/com17/languages/X.680-0207.pdf
+ *	http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf
+ */
+
+#include "x509.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+
+/*
+ * ASN.1 DER decoding routines
+ */
+static int asn1_get_len(unsigned char **p, const unsigned char *end, int *len)
+{
+	if ((end - *p) < 1)
+		return (TROPICSSL_ERR_ASN1_OUT_OF_DATA);
+
+	if ((**p & 0x80) == 0)
+		*len = *(*p)++;
+	else {
+		switch (**p & 0x7F) {
+		case 1:
+			if ((end - *p) < 2)
+				return (TROPICSSL_ERR_ASN1_OUT_OF_DATA);
+
+			*len = (*p)[1];
+			(*p) += 2;
+			break;
+
+		case 2:
+			if ((end - *p) < 3)
+				return (TROPICSSL_ERR_ASN1_OUT_OF_DATA);
+
+			*len = ((*p)[1] << 8) | (*p)[2];
+			(*p) += 3;
+			break;
+
+		default:
+			return (TROPICSSL_ERR_ASN1_INVALID_LENGTH);
+			break;
+		}
+	}
+
+	if (*len > (int)(end - *p))
+		return (TROPICSSL_ERR_ASN1_OUT_OF_DATA);
+
+	return (0);
+}
+
+static int asn1_get_tag(unsigned char **p,
+			const unsigned char *end, int *len, int tag)
+{
+	if ((end - *p) < 1)
+		return (TROPICSSL_ERR_ASN1_OUT_OF_DATA);
+
+	if (**p != tag)
+		return (TROPICSSL_ERR_ASN1_UNEXPECTED_TAG);
+
+	(*p)++;
+
+	return (asn1_get_len(p, end, len));
+}
+
+static int asn1_get_int(unsigned char **p, const unsigned char *end, int *val)
+{
+	int ret, len;
+
+	if ((ret = asn1_get_tag(p, end, &len, ASN1_INTEGER)) != 0)
+		return (ret);
+
+	if (len > (int)sizeof(int) || (**p & 0x80) != 0)
+		return (TROPICSSL_ERR_ASN1_INVALID_LENGTH);
+
+	*val = 0;
+
+	while (len-- > 0) {
+		*val = (*val << 8) | **p;
+		(*p)++;
+	}
+
+	return (0);
+}
+
+/*
+ *	Version	 ::=  INTEGER  {  v1(0), v2(1), v3(2)  }
+ */
+static int x509_get_version(unsigned char **p, const unsigned char *end, int *ver)
+{
+	int ret, len;
+
+	if ((ret = asn1_get_tag(p, end, &len,
+				ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 0))
+	    != 0) {
+		if (ret == TROPICSSL_ERR_ASN1_UNEXPECTED_TAG)
+			return (*ver = 0);
+
+		return (ret);
+	}
+
+	end = *p + len;
+
+	if ((ret = asn1_get_int(p, end, ver)) != 0)
+		return (TROPICSSL_ERR_X509_CERT_INVALID_VERSION | ret);
+
+	if (*p != end)
+		return (TROPICSSL_ERR_X509_CERT_INVALID_VERSION |
+			TROPICSSL_ERR_ASN1_LENGTH_MISMATCH);
+
+	return (0);
+}
+
+/*
+ *	CertificateSerialNumber	 ::=  INTEGER
+ */
+static int x509_get_serial(unsigned char **p,
+			   const unsigned char *end, x509_buf * serial)
+{
+	int ret;
+
+	if ((end - *p) < 1)
+		return (TROPICSSL_ERR_X509_CERT_INVALID_SERIAL |
+			TROPICSSL_ERR_ASN1_OUT_OF_DATA);
+
+	if (**p != (ASN1_CONTEXT_SPECIFIC | ASN1_PRIMITIVE | 2) &&
+	    **p != ASN1_INTEGER)
+		return (TROPICSSL_ERR_X509_CERT_INVALID_SERIAL |
+			TROPICSSL_ERR_ASN1_UNEXPECTED_TAG);
+
+	serial->tag = *(*p)++;
+
+	if ((ret = asn1_get_len(p, end, &serial->len)) != 0)
+		return (TROPICSSL_ERR_X509_CERT_INVALID_SERIAL | ret);
+
+	serial->p = *p;
+	*p += serial->len;
+
+	return (0);
+}
+
+/*
+ *	AlgorithmIdentifier	 ::=  SEQUENCE	{
+ *		 algorithm				 OBJECT IDENTIFIER,
+ *		 parameters				 ANY DEFINED BY algorithm OPTIONAL	}
+ */
+static int x509_get_alg(unsigned char **p, const unsigned char *end, x509_buf * alg)
+{
+	int ret, len;
+
+	if ((ret = asn1_get_tag(p, end, &len,
+				ASN1_CONSTRUCTED | ASN1_SEQUENCE)) != 0)
+		return (TROPICSSL_ERR_X509_CERT_INVALID_ALG | ret);
+
+	end = *p + len;
+	alg->tag = **p;
+
+	if ((ret = asn1_get_tag(p, end, &alg->len, ASN1_OID)) != 0)
+		return (TROPICSSL_ERR_X509_CERT_INVALID_ALG | ret);
+
+	alg->p = *p;
+	*p += alg->len;
+
+	if (*p == end)
+		return (0);
+
+	/*
+	 * assume the algorithm parameters must be NULL
+	 */
+	if ((ret = asn1_get_tag(p, end, &len, ASN1_NULL)) != 0)
+		return (TROPICSSL_ERR_X509_CERT_INVALID_ALG | ret);
+
+	if (*p != end)
+		return (TROPICSSL_ERR_X509_CERT_INVALID_ALG |
+			TROPICSSL_ERR_ASN1_LENGTH_MISMATCH);
+
+	return (0);
+}
+
+/*
+ *	RelativeDistinguishedName ::=
+ *	  SET OF AttributeTypeAndValue
+ *
+ *	AttributeTypeAndValue ::= SEQUENCE {
+ *	  type	   AttributeType,
+ *	  value	   AttributeValue }
+ *
+ *	AttributeType ::= OBJECT IDENTIFIER
+ *
+ *	AttributeValue ::= ANY DEFINED BY AttributeType
+ */
+static int x509_get_name(unsigned char **p, const unsigned char *end, x509_name * cur)
+{
+	int ret, len;
+	const unsigned char *end2;
+	x509_buf *oid;
+	x509_buf *val;
+
+	if ((ret = asn1_get_tag(p, end, &len,
+				ASN1_CONSTRUCTED | ASN1_SET)) != 0)
+		return (TROPICSSL_ERR_X509_CERT_INVALID_NAME | ret);
+
+	end2 = end;
+	end = *p + len;
+
+	if ((ret = asn1_get_tag(p, end, &len,
+				ASN1_CONSTRUCTED | ASN1_SEQUENCE)) != 0)
+		return (TROPICSSL_ERR_X509_CERT_INVALID_NAME | ret);
+
+	if (*p + len != end)
+		return (TROPICSSL_ERR_X509_CERT_INVALID_NAME |
+			TROPICSSL_ERR_ASN1_LENGTH_MISMATCH);
+
+	oid = &cur->oid;
+	oid->tag = **p;
+
+	if ((ret = asn1_get_tag(p, end, &oid->len, ASN1_OID)) != 0)
+		return (TROPICSSL_ERR_X509_CERT_INVALID_NAME | ret);
+
+	oid->p = *p;
+	*p += oid->len;
+
+	if ((end - *p) < 1)
+		return (TROPICSSL_ERR_X509_CERT_INVALID_NAME |
+			TROPICSSL_ERR_ASN1_OUT_OF_DATA);
+
+	if (**p != ASN1_BMP_STRING && **p != ASN1_UTF8_STRING &&
+	    **p != ASN1_T61_STRING && **p != ASN1_PRINTABLE_STRING &&
+	    **p != ASN1_IA5_STRING && **p != ASN1_UNIVERSAL_STRING)
+		return (TROPICSSL_ERR_X509_CERT_INVALID_NAME |
+			TROPICSSL_ERR_ASN1_UNEXPECTED_TAG);
+
+	val = &cur->val;
+	val->tag = *(*p)++;
+
+	if ((ret = asn1_get_len(p, end, &val->len)) != 0)
+		return (TROPICSSL_ERR_X509_CERT_INVALID_NAME | ret);
+
+	val->p = *p;
+	*p += val->len;
+
+	cur->next = NULL;
+
+	if (*p != end)
+		return (TROPICSSL_ERR_X509_CERT_INVALID_NAME |
+			TROPICSSL_ERR_ASN1_LENGTH_MISMATCH);
+
+	/*
+	 * recurse until end of SEQUENCE is reached
+	 */
+	if (*p == end2)
+		return (0);
+
+	cur->next = (x509_name *) malloc(sizeof(x509_name));
+
+	if (cur->next == NULL)
+		return (1);
+
+	return (x509_get_name(p, end2, cur->next));
+}
+
+/*
+ *	Validity ::= SEQUENCE {
+ *		 notBefore		Time,
+ *		 notAfter		Time }
+ *
+ *	Time ::= CHOICE {
+ *		 utcTime		UTCTime,
+ *		 generalTime	GeneralizedTime }
+ */
+static int x509_get_dates(unsigned char **p,
+			  const unsigned char *end, x509_time * from, x509_time * to)
+{
+	int ret, len;
+	char date[64];
+
+	if ((ret = asn1_get_tag(p, end, &len,
+				ASN1_CONSTRUCTED | ASN1_SEQUENCE)) != 0)
+		return (TROPICSSL_ERR_X509_CERT_INVALID_DATE | ret);
+
+	end = *p + len;
+
+	/*
+	 * TODO: also handle GeneralizedTime
+	 */
+	if ((ret = asn1_get_tag(p, end, &len, ASN1_UTC_TIME)) != 0)
+		return (TROPICSSL_ERR_X509_CERT_INVALID_DATE | ret);
+
+	memset(date, 0, sizeof(date));
+	memcpy(date, *p, (len < (int)sizeof(date) - 1) ?
+	       len : (int)sizeof(date) - 1);
+
+	if (sscanf(date, "%2d%2d%2d%2d%2d%2d",
+		   &from->year, &from->mon, &from->day,
+		   &from->hour, &from->min, &from->sec) < 5)
+		return (TROPICSSL_ERR_X509_CERT_INVALID_DATE);
+
+	from->year += 100 * (from->year < 90);
+	from->year += 1900;
+
+	*p += len;
+
+	if ((ret = asn1_get_tag(p, end, &len, ASN1_UTC_TIME)) != 0)
+		return (TROPICSSL_ERR_X509_CERT_INVALID_DATE | ret);
+
+	memset(date, 0, sizeof(date));
+	memcpy(date, *p, (len < (int)sizeof(date) - 1) ?
+	       len : (int)sizeof(date) - 1);
+
+	if (sscanf(date, "%2d%2d%2d%2d%2d%2d",
+		   &to->year, &to->mon, &to->day,
+		   &to->hour, &to->min, &to->sec) < 5)
+		return (TROPICSSL_ERR_X509_CERT_INVALID_DATE);
+
+	to->year += 100 * (to->year < 90);
+	to->year += 1900;
+
+	*p += len;
+
+	if (*p != end)
+		return (TROPICSSL_ERR_X509_CERT_INVALID_DATE |
+			TROPICSSL_ERR_ASN1_LENGTH_MISMATCH);
+
+	return (0);
+}
+
+static int x509_get_sig(unsigned char **p, const unsigned char *end, x509_buf * sig)
+{
+	int ret, len;
+
+	sig->tag = **p;
+
+	if ((ret = asn1_get_tag(p, end, &len, ASN1_BIT_STRING)) != 0)
+		return (TROPICSSL_ERR_X509_CERT_INVALID_SIGNATURE | ret);
+
+	if (--len < 1 || *(*p)++ != 0)
+		return (TROPICSSL_ERR_X509_CERT_INVALID_SIGNATURE);
+
+	sig->len = len;
+	sig->p = *p;
+
+	*p += len;
+
+	return (0);
+}
+
+/*
+ * X.509 v2/v3 unique identifier (not parsed)
+ */
+static int x509_get_uid(unsigned char **p,
+			const unsigned char *end, x509_buf * uid, int n)
+{
+	int ret;
+
+	if (*p == end)
+		return (0);
+
+	uid->tag = **p;
+
+	if ((ret = asn1_get_tag(p, end, &uid->len,
+				ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | n))
+	    != 0) {
+		if (ret == TROPICSSL_ERR_ASN1_UNEXPECTED_TAG)
+			return (0);
+
+		return (ret);
+	}
+
+	uid->p = *p;
+	*p += uid->len;
+
+	return (0);
+}
+
+/*
+ * Parse one certificate.
+ */
+static int _x509parse_crt_1(x509_cert * chain, unsigned char *buf, int buflen)
+{
+	int ret, len;
+	unsigned char *p;
+	const unsigned char *end;
+	x509_cert *crt;
+
+	crt = chain;
+
+	/*
+	 * Copy the raw DER data.
+	 */
+	p = (unsigned char *)malloc(len = buflen);
+
+	if (p == NULL)
+		return (1);
+
+	memcpy(p, buf, buflen);
+
+	buflen = 0;
+
+	crt->raw.p = p;
+	crt->raw.len = len;
+	end = p + len;
+
+	/*
+	 * Certificate  ::=      SEQUENCE  {
+	 *              tbsCertificate           TBSCertificate,
+	 *              signatureAlgorithm       AlgorithmIdentifier,
+	 *              signatureValue           BIT STRING      }
+	 */
+	if ((ret = asn1_get_tag(&p, end, &len,
+				ASN1_CONSTRUCTED | ASN1_SEQUENCE)) != 0) {
+		x509_free(crt);
+		return (TROPICSSL_ERR_X509_CERT_INVALID_FORMAT);
+	}
+
+	if (len != (int)(end - p)) {
+		x509_free(crt);
+		return (TROPICSSL_ERR_X509_CERT_INVALID_FORMAT |
+			TROPICSSL_ERR_ASN1_LENGTH_MISMATCH);
+	}
+
+	/*
+	 * TBSCertificate  ::=  SEQUENCE  {
+	 */
+	crt->tbs.p = p;
+
+	if ((ret = asn1_get_tag(&p, end, &len,
+				ASN1_CONSTRUCTED | ASN1_SEQUENCE)) != 0) {
+		x509_free(crt);
+		return (TROPICSSL_ERR_X509_CERT_INVALID_FORMAT | ret);
+	}
+
+	end = p + len;
+	crt->tbs.len = end - crt->tbs.p;
+
+	/*
+	 * Version      ::=      INTEGER  {      v1(0), v2(1), v3(2)  }
+	 *
+	 * CertificateSerialNumber      ::=      INTEGER
+	 *
+	 * signature                    AlgorithmIdentifier
+	 */
+	if ((ret = x509_get_version(&p, end, &crt->version)) != 0 ||
+	    (ret = x509_get_serial(&p, end, &crt->serial)) != 0 ||
+	    (ret = x509_get_alg(&p, end, &crt->sig_oid1)) != 0) {
+		x509_free(crt);
+		return (ret);
+	}
+
+	crt->version++;
+
+	if (crt->version > 3) {
+		x509_free(crt);
+		return (TROPICSSL_ERR_X509_CERT_UNKNOWN_VERSION);
+	}
+
+	if (crt->sig_oid1.len != 9 ||
+	    memcmp(crt->sig_oid1.p, OID_PKCS1, 8) != 0) {
+		x509_free(crt);
+		return (TROPICSSL_ERR_X509_CERT_UNKNOWN_SIG_ALG);
+	}
+
+	if (crt->sig_oid1.p[8] < 2 || crt->sig_oid1.p[8] > 5) {
+		x509_free(crt);
+		return (TROPICSSL_ERR_X509_CERT_UNKNOWN_SIG_ALG);
+	}
+
+	/*
+	 * issuer                               Name
+	 */
+	crt->issuer_raw.p = p;
+
+	if ((ret = asn1_get_tag(&p, end, &len,
+				ASN1_CONSTRUCTED | ASN1_SEQUENCE)) != 0) {
+		x509_free(crt);
+		return (TROPICSSL_ERR_X509_CERT_INVALID_FORMAT | ret);
+	}
+
+	if ((ret = x509_get_name(&p, p + len, &crt->issuer)) != 0) {
+		x509_free(crt);
+		return (ret);
+	}
+
+	crt->issuer_raw.len = p - crt->issuer_raw.p;
+
+	/*
+	 * Validity ::= SEQUENCE {
+	 *              notBefore          Time,
+	 *              notAfter           Time }
+	 *
+	 */
+	if ((ret = x509_get_dates(&p, end, &crt->valid_from,
+				  &crt->valid_to)) != 0) {
+		x509_free(crt);
+		return (ret);
+	}
+
+	/*
+	 * subject                              Name
+	 */
+	crt->subject_raw.p = p;
+
+	if ((ret = asn1_get_tag(&p, end, &len,
+				ASN1_CONSTRUCTED | ASN1_SEQUENCE)) != 0) {
+		x509_free(crt);
+		return (TROPICSSL_ERR_X509_CERT_INVALID_FORMAT | ret);
+	}
+
+	if ((ret = x509_get_name(&p, p + len, &crt->subject)) != 0) {
+		x509_free(crt);
+		return (ret);
+	}
+
+	crt->subject_raw.len = p - crt->subject_raw.p;
+
+	/*
+	 * SubjectPublicKeyInfo  ::=  SEQUENCE
+	 *              algorithm                        AlgorithmIdentifier,
+	 *              subjectPublicKey         BIT STRING      }
+	 */
+	if ((ret = asn1_get_tag(&p, end, &len,
+				ASN1_CONSTRUCTED | ASN1_SEQUENCE)) != 0) {
+		x509_free(crt);
+		return (TROPICSSL_ERR_X509_CERT_INVALID_FORMAT | ret);
+	}
+
+  /* Skip pubkey. */
+  p += len;
+
+	/*
+	 *      issuerUniqueID  [1]      IMPLICIT UniqueIdentifier OPTIONAL,
+	 *                                               -- If present, version shall be v2 or v3
+	 *      subjectUniqueID [2]      IMPLICIT UniqueIdentifier OPTIONAL,
+	 *                                               -- If present, version shall be v2 or v3
+	 *      extensions              [3]      EXPLICIT Extensions OPTIONAL
+	 *                                               -- If present, version shall be v3
+	 */
+	if (crt->version == 2 || crt->version == 3) {
+		ret = x509_get_uid(&p, end, &crt->issuer_id, 1);
+		if (ret != 0) {
+			x509_free(crt);
+			return (ret);
+		}
+	}
+
+	if (crt->version == 2 || crt->version == 3) {
+		ret = x509_get_uid(&p, end, &crt->subject_id, 2);
+		if (ret != 0) {
+			x509_free(crt);
+			return (ret);
+		}
+	}
+
+	if (p != end) {
+		x509_free(crt);
+		return (TROPICSSL_ERR_X509_CERT_INVALID_FORMAT |
+			TROPICSSL_ERR_ASN1_LENGTH_MISMATCH);
+	}
+
+	end = crt->raw.p + crt->raw.len;
+
+	/*
+	 *      signatureAlgorithm       AlgorithmIdentifier,
+	 *      signatureValue           BIT STRING
+	 */
+	if ((ret = x509_get_alg(&p, end, &crt->sig_oid2)) != 0) {
+		x509_free(crt);
+		return (ret);
+	}
+
+	if (memcmp(crt->sig_oid1.p, crt->sig_oid2.p, 9) != 0) {
+		x509_free(crt);
+		return (TROPICSSL_ERR_X509_CERT_SIG_MISMATCH);
+	}
+
+	if ((ret = x509_get_sig(&p, end, &crt->sig)) != 0) {
+		x509_free(crt);
+		return (ret);
+	}
+
+	if (p != end) {
+		x509_free(crt);
+		return (TROPICSSL_ERR_X509_CERT_INVALID_FORMAT |
+			TROPICSSL_ERR_ASN1_LENGTH_MISMATCH);
+	}
+
+	return (0);
+}
+
+/*
+ * Parse one or more certificates and add them to the chained list
+ */
+int x509parse_crt(x509_cert * chain, const unsigned char *buf, int buflen)
+{
+	int ret;
+	unsigned char *buf1 = malloc(buflen);
+	if (buf1 == NULL) {
+		  return (1);
+	}
+	memcpy(buf1, buf, buflen);
+	ret = _x509parse_crt_1(chain, buf1, buflen);
+	free(buf1);
+	return ret;
+}
+
+/*
+ * Unallocate all certificate data
+ */
+void x509_free(x509_cert * crt)
+{
+	x509_name *name_cur;
+	x509_name *name_prv;
+
+	if (crt == NULL)
+		return;
+
+	name_cur = crt->issuer.next;
+	while (name_cur != NULL) {
+		name_prv = name_cur;
+		name_cur = name_cur->next;
+		memset(name_prv, 0, sizeof(x509_name));
+		free(name_prv);
+	}
+
+	name_cur = crt->subject.next;
+	while (name_cur != NULL) {
+		name_prv = name_cur;
+		name_cur = name_cur->next;
+		memset(name_prv, 0, sizeof(x509_name));
+		free(name_prv);
+	}
+
+	if (crt->raw.p != NULL) {
+		memset(crt->raw.p, 0, crt->raw.len);
+		free(crt->raw.p);
+	}
+
+	memset(crt, 0, sizeof(x509_cert));
+	free(crt);
+}