1 /* Support of PKCS#1 and PKCS#7 data structures
2 * Copyright (C) 2002 Andreas Steffen, Zuercher Hochschule Winterthur
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * RCSID $Id: pkcs.c,v 0.1 2002/04/12 00:00:00 as Exp $
22 #include "constants.h"
30 /* ASN.1 definition of a PKCS#1 RSA private key */
32 static const asn1Object_t privkeyObjects[] = {
33 { 0, "RSAPrivateKey", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */
34 { 1, "version", ASN1_INTEGER, ASN1_BODY }, /* 1 */
35 { 1, "modulus", ASN1_INTEGER, ASN1_BODY }, /* 2 */
36 { 1, "publicExponent", ASN1_INTEGER, ASN1_BODY }, /* 3 */
37 { 1, "privateExponent", ASN1_INTEGER, ASN1_BODY }, /* 4 */
38 { 1, "prime1", ASN1_INTEGER, ASN1_BODY }, /* 5 */
39 { 1, "prime2", ASN1_INTEGER, ASN1_BODY }, /* 6 */
40 { 1, "exponent1", ASN1_INTEGER, ASN1_BODY }, /* 7 */
41 { 1, "exponent2", ASN1_INTEGER, ASN1_BODY }, /* 8 */
42 { 1, "coefficient", ASN1_INTEGER, ASN1_BODY }, /* 9 */
43 { 1, "otherPrimeInfos", ASN1_SEQUENCE, ASN1_OPT |
45 { 2, "otherPrimeInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 11 */
46 { 3, "prime", ASN1_INTEGER, ASN1_BODY }, /* 12 */
47 { 3, "exponent", ASN1_INTEGER, ASN1_BODY }, /* 13 */
48 { 3, "coefficient", ASN1_INTEGER, ASN1_BODY }, /* 14 */
49 { 1, "end opt or loop", ASN1_EOC, ASN1_END } /* 15 */
52 #define PKCS1_PRIV_KEY_OBJECT 0
53 #define PKCS1_PRIV_KEY_VERSION 1
54 #define PKCS1_PRIV_KEY_MODULUS 2
55 #define PKCS1_PRIV_KEY_COEFF 9
56 #define PKCS1_PRIV_KEY_ROOF 16
58 /* ASN.1 definition of the PKCS#7 ContentInfo type */
60 static const asn1Object_t contentInfoObjects[] = {
61 { 0, "contentInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
62 { 1, "contentType", ASN1_OID, ASN1_BODY }, /* 1 */
63 { 1, "content", ASN1_CONTEXT_C_0, ASN1_OPT |
65 { 1, "end opt", ASN1_EOC, ASN1_END } /* 3 */
68 #define PKCS7_INFO_TYPE 1
69 #define PKCS7_INFO_CONTENT 2
70 #define PKCS7_INFO_ROOF 4
72 /* ASN.1 definition of the PKCS#7 SignedData type */
74 static const asn1Object_t signedDataObjects[] = {
75 { 0, "signedData", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
76 { 1, "version", ASN1_INTEGER, ASN1_BODY }, /* 1 */
77 { 1, "digestAlgorithms", ASN1_SET, ASN1_BODY }, /* 2 */
78 { 1, "contentInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 3 */
79 { 1, "certificates", ASN1_CONTEXT_C_0, ASN1_OPT |
81 { 2, "certificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 5 */
82 { 1, "end opt or loop", ASN1_EOC, ASN1_END }, /* 6 */
83 { 1, "crls", ASN1_CONTEXT_C_1, ASN1_OPT |
85 { 2, "crl", ASN1_SEQUENCE, ASN1_OBJ }, /* 8 */
86 { 1, "end opt or loop", ASN1_EOC, ASN1_END }, /* 9 */
87 { 1, "signerInfos", ASN1_SET, ASN1_BODY } /* 10 */
90 #define PKCS7_SIGNED_CERT 5
91 #define PKCS7_SIGNED_ROOF 11
93 /* used for initialization */
95 const pkcs1privkey_t empty_pkcs1privkey = {
96 { NULL, 1 }, /* pkcs1object */
98 { NULL, 1 },{ NULL, 1 },{ NULL, 1 },{ NULL, 1 },
99 { NULL, 1 },{ NULL, 1 },{ NULL, 1 },{ NULL, 1 }
104 * Parses a PKCS#1 private key
107 parse_pkcs1_private_key(chunk_t blob, pkcs1privkey_t *key)
113 asn1_init(&ctx, blob, 0, FALSE, DBG_PRIVATE);
115 while (objectID < PKCS1_PRIV_KEY_ROOF) {
117 if (!extract_object(privkeyObjects, &objectID, &object, &ctx))
120 if (objectID == PKCS1_PRIV_KEY_OBJECT)
122 key->pkcs1object = object;
124 else if (objectID == PKCS1_PRIV_KEY_VERSION)
126 if (*object.ptr != 0)
128 log(" wrong PKCS#1 private key version");
132 else if (objectID >= PKCS1_PRIV_KEY_MODULUS &&
133 objectID <= PKCS1_PRIV_KEY_COEFF)
135 key->field[objectID - PKCS1_PRIV_KEY_MODULUS] = object;
143 * Loads PKCS#1 private key file
146 load_pkcs1_private_key(const char* filename, const char* passphrase)
148 chunk_t blob = empty_chunk;
151 if (*filename == '/') /* absolute pathname */
152 strncpy(path, filename, sizeof(path));
153 else /* relative pathname */
154 snprintf(path, sizeof(path), "%s/%s", PRIVATE_KEY_PATH, filename);
156 if (load_asn1_file(path, passphrase, "private key", &blob))
158 pkcs1privkey_t *key = alloc_thing(pkcs1privkey_t, "pkcs1privkey");
159 *key = empty_pkcs1privkey;
160 if (parse_pkcs1_private_key(blob, key))
164 log(" error in PKCS#1 private key");
173 * Parse PKCS#7 wrapped X.509 certificates
176 parse_pkcs7_signedData(chunk_t blob, int level0, x509cert_t **cert)
182 asn1_init(&ctx, blob, level0, FALSE, DBG_RAW);
184 while (objectID < PKCS7_SIGNED_ROOF) {
186 if (!extract_object(signedDataObjects, &objectID, &object, &ctx))
189 if (objectID == PKCS7_SIGNED_CERT)
191 u_int level = level0 + signedDataObjects[objectID].level;
193 x509cert_t *newcert = alloc_thing(x509cert_t,
194 "pkcs7 wrapped x509cert");
196 clonetochunk(cert_blob, object.ptr, object.len, "pkcs7 cert blob");
197 *newcert = empty_x509cert;
199 if (parse_x509cert(cert_blob, level, newcert))
201 newcert->next = *cert;
206 free_x509cert(newcert);
215 * Parse PKCS#7 wrapped X.509 certificates
218 parse_pkcs7_cert(chunk_t blob, x509cert_t **cert)
224 asn1_init(&ctx, blob, 0, FALSE, DBG_RAW);
226 while (objectID < PKCS7_INFO_ROOF) {
228 if (!extract_object(contentInfoObjects, &objectID, &object, &ctx))
231 if (objectID == PKCS7_INFO_TYPE)
233 if (known_oid(object) != OID_PKCS7_SIGNED_DATA)
235 log("PKCS#7 content type is not signedData");
239 else if (objectID == PKCS7_INFO_CONTENT)
241 u_int level = contentInfoObjects[objectID].level + 1;
243 parse_pkcs7_signedData(object, level, cert);