OSDN Git Service

2013.10.24
[uclinux-h8/uClinux-dist.git] / freeswan / pluto / pkcs.c
1 /* Support of PKCS#1 and PKCS#7 data structures
2  * Copyright (C) 2002 Andreas Steffen, Zuercher Hochschule Winterthur
3  *
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>.
8  *
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
12  * for more details.
13  *
14  * RCSID $Id: pkcs.c,v 0.1 2002/04/12 00:00:00 as Exp $
15  */
16
17 #include <stdlib.h>
18 #include <string.h>
19
20 #include <freeswan.h>
21
22 #include "constants.h"
23 #include "defs.h"
24 #include "asn1.h"
25 #include "log.h"
26 #include "id.h"
27 #include "x509.h"
28 #include "pkcs.h"
29
30 /* ASN.1 definition of a PKCS#1 RSA private key */
31
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 |
44                                                            ASN1_LOOP }, /* 10 */
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 */
50 };
51
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
57
58 /* ASN.1 definition of the PKCS#7 ContentInfo type */
59
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 |
64                                                            ASN1_BODY }, /*  2 */
65   { 1,   "end opt",                     ASN1_EOC,          ASN1_END  }  /*  3 */
66 };
67
68 #define PKCS7_INFO_TYPE         1
69 #define PKCS7_INFO_CONTENT      2
70 #define PKCS7_INFO_ROOF         4
71
72 /* ASN.1 definition of the PKCS#7 SignedData type */
73
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 |
80                                                            ASN1_LOOP }, /*  4 */
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 |
84                                                            ASN1_LOOP }, /*  7 */
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 */
88 };
89
90 #define PKCS7_SIGNED_CERT        5
91 #define PKCS7_SIGNED_ROOF       11
92
93 /* used for initialization */
94
95 const pkcs1privkey_t empty_pkcs1privkey = {
96     { NULL, 1 }, /* pkcs1object */
97     {
98         { NULL, 1 },{ NULL, 1 },{ NULL, 1 },{ NULL, 1 },
99         { NULL, 1 },{ NULL, 1 },{ NULL, 1 },{ NULL, 1 }
100     }            /* field[0..7] */
101 };
102
103 /*
104  *  Parses a PKCS#1 private key
105  */
106 bool
107 parse_pkcs1_private_key(chunk_t blob, pkcs1privkey_t *key)
108 {
109     asn1_ctx_t ctx;
110     chunk_t object;
111     int objectID = 0;
112
113     asn1_init(&ctx, blob, 0, FALSE, DBG_PRIVATE);
114
115     while (objectID < PKCS1_PRIV_KEY_ROOF) {
116
117         if (!extract_object(privkeyObjects, &objectID, &object, &ctx))
118              return FALSE;
119
120         if (objectID == PKCS1_PRIV_KEY_OBJECT)
121         {
122             key->pkcs1object = object;
123         }
124         else if (objectID == PKCS1_PRIV_KEY_VERSION)
125         {
126             if (*object.ptr != 0)
127             {
128                 log("  wrong PKCS#1 private key version");
129                 return FALSE;
130             }
131         }
132         else if (objectID >= PKCS1_PRIV_KEY_MODULUS &&
133                  objectID <= PKCS1_PRIV_KEY_COEFF)
134         {
135             key->field[objectID - PKCS1_PRIV_KEY_MODULUS] = object;
136         }
137         objectID++;
138     }
139     return TRUE;
140 }
141
142 /*
143  *  Loads PKCS#1 private key file
144  */
145 pkcs1privkey_t*
146 load_pkcs1_private_key(const char* filename, const char* passphrase)
147 {
148     chunk_t blob = empty_chunk;
149     char path[512];
150
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);
155
156     if (load_asn1_file(path, passphrase, "private key", &blob))
157     {
158         pkcs1privkey_t *key = alloc_thing(pkcs1privkey_t, "pkcs1privkey");
159         *key = empty_pkcs1privkey;
160         if (parse_pkcs1_private_key(blob, key))
161             return key;
162         else
163         {
164             log("  error in PKCS#1 private key");
165             pfree(blob.ptr);
166             pfree(key);
167         }
168     }
169     return NULL;
170 }
171
172 /*
173  * Parse PKCS#7 wrapped X.509 certificates
174  */
175 static bool
176 parse_pkcs7_signedData(chunk_t blob, int level0, x509cert_t **cert)
177 {
178     asn1_ctx_t ctx;
179     chunk_t object;
180     int objectID = 0;
181
182     asn1_init(&ctx, blob, level0, FALSE, DBG_RAW);
183
184     while (objectID < PKCS7_SIGNED_ROOF) {
185
186         if (!extract_object(signedDataObjects, &objectID, &object, &ctx))
187              return FALSE;
188
189         if (objectID == PKCS7_SIGNED_CERT)
190         {
191             u_int level = level0 + signedDataObjects[objectID].level;
192             chunk_t cert_blob;
193             x509cert_t *newcert = alloc_thing(x509cert_t,
194                                         "pkcs7 wrapped x509cert");
195
196             clonetochunk(cert_blob, object.ptr, object.len, "pkcs7 cert blob");
197             *newcert = empty_x509cert;
198
199             if (parse_x509cert(cert_blob, level, newcert))
200             {
201                 newcert->next = *cert;
202                 *cert = newcert;
203             }
204             else
205             {
206                 free_x509cert(newcert);
207             }
208         }
209         objectID++;
210     }
211     return TRUE;
212 }
213
214 /*
215  * Parse PKCS#7 wrapped X.509 certificates
216  */
217 bool
218 parse_pkcs7_cert(chunk_t blob, x509cert_t **cert)
219 {
220     asn1_ctx_t ctx;
221     chunk_t object;
222     int objectID = 0;
223
224     asn1_init(&ctx, blob, 0, FALSE, DBG_RAW);
225
226     while (objectID < PKCS7_INFO_ROOF) {
227
228         if (!extract_object(contentInfoObjects, &objectID, &object, &ctx))
229              return FALSE;
230
231         if (objectID == PKCS7_INFO_TYPE)
232         {
233             if (known_oid(object) != OID_PKCS7_SIGNED_DATA)
234             {
235                 log("PKCS#7 content type is not signedData");
236                 return FALSE;
237             }
238         }
239         else if (objectID == PKCS7_INFO_CONTENT)
240         {
241             u_int level = contentInfoObjects[objectID].level + 1;
242
243             parse_pkcs7_signedData(object, level, cert);
244         }
245         objectID++;
246     }
247     return TRUE;
248 }
249