pluto and scepclient use private and public key plugins of libstrongswan
[strongswan.git] / src / scepclient / pkcs10.c
1 /**
2 * @file pkcs10.c
3 * @brief Functions to build PKCS#10 requests
4 *
5 * Contains functions to build DER encoded pkcs#10 certificate requests
6 */
7
8 /* Copyright (C) 2005 Jan Hutter, Martin Willi
9 * Hochschule fuer Technik Rapperswil
10 *
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by the
13 * Free Software Foundation; either version 2 of the License, or (at your
14 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
15 *
16 * This program is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
18 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 * for more details.
20 */
21
22 #include <stdlib.h>
23 #include <string.h>
24 #include <sys/socket.h>
25 #include <netinet/in.h>
26 #include <arpa/inet.h>
27
28 #include <freeswan.h>
29 #include <asn1/asn1.h>
30 #include <asn1/oid.h>
31
32 #include "../pluto/constants.h"
33 #include "../pluto/defs.h"
34 #include "../pluto/log.h"
35 #include "../pluto/x509.h"
36
37 #include "pkcs10.h"
38
39 /* some pre-coded OIDs */
40
41 static u_char ASN1_challengePassword_oid_str[] = {
42 0x06,0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x07
43 };
44
45 static const chunk_t ASN1_challengePassword_oid = chunk_from_buf(ASN1_challengePassword_oid_str);
46
47 static u_char ASN1_extensionRequest_oid_str[] = {
48 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x0E
49 };
50
51 static const chunk_t ASN1_extensionRequest_oid = chunk_from_buf(ASN1_extensionRequest_oid_str);
52
53 /**
54 * @brief Adds a subjectAltName in DER-coded form to a linked list
55 *
56 * @param[in,out] subjectAltNames head of the linked list of subjectAltNames
57 * @param[in] kind type of the subjectAltName (which is a generalName)
58 * @param[in] value value of the subjectAltName as an ASCII string
59 */
60 void
61 pkcs10_add_subjectAltName(generalName_t **subjectAltNames, generalNames_t kind
62 , char *value)
63 {
64 generalName_t *gn;
65 asn1_t asn1_type = ASN1_EOC;
66 chunk_t name = { value, strlen(value) };
67
68 switch (kind)
69 {
70 case GN_RFC822_NAME:
71 asn1_type = ASN1_CONTEXT_S_1;
72 break;
73 case GN_DNS_NAME:
74 asn1_type = ASN1_CONTEXT_S_2;
75 break;
76 case GN_IP_ADDRESS:
77 {
78 struct in_addr addr;
79
80 /* convert an ASCII dotted IPv4 address (e.g. 123.456.78.90)
81 * to a byte representation in network order
82 */
83 if (!inet_aton(value, &addr))
84 {
85 fprintf(stderr, "error in IPv4 subjectAltName\n");
86 return;
87 }
88 asn1_type = ASN1_CONTEXT_S_7;
89 name.ptr = (u_char *) &addr.s_addr;
90 name.len = sizeof(addr.s_addr);
91 break;
92 }
93 default:
94 break;
95 }
96
97 gn = malloc_thing(generalName_t);
98 gn->kind = kind;
99 gn->name = asn1_simple_object(asn1_type, name);
100 gn->next = *subjectAltNames;
101 *subjectAltNames = gn;
102 }
103
104 /**
105 * @brief Builds the requestInfoAttributes of the certificationRequestInfo-field
106 *
107 * challenge password ans subjectAltNames are only included,
108 * when avaiable in given #pkcs10_t structure
109 *
110 * @param[in] pkcs10 Pointer to a #pkcs10_t structure
111 * @return 1 if succeeded, 0 otherwise
112 */
113 static chunk_t
114 build_req_info_attributes(pkcs10_t* pkcs10)
115 {
116
117 chunk_t subjectAltNames = chunk_empty;
118 chunk_t challengePassword = chunk_empty;
119
120 if (pkcs10->subjectAltNames != NULL)
121 {
122
123 subjectAltNames = asn1_wrap(ASN1_SEQUENCE, "cm"
124 , ASN1_extensionRequest_oid
125 , asn1_wrap(ASN1_SET, "m"
126 , asn1_wrap(ASN1_SEQUENCE, "m"
127 , build_subjectAltNames(pkcs10->subjectAltNames)
128 )
129 )
130 );
131 }
132
133 if (pkcs10->challengePassword.len > 0)
134 {
135 asn1_t type = asn1_is_printablestring(pkcs10->challengePassword)
136 ? ASN1_PRINTABLESTRING : ASN1_T61STRING;
137
138 challengePassword = asn1_wrap(ASN1_SEQUENCE, "cm"
139 , ASN1_challengePassword_oid
140 , asn1_wrap(ASN1_SET, "m"
141 , asn1_simple_object(type, pkcs10->challengePassword)
142 )
143 );
144 }
145
146 return asn1_wrap(ASN1_CONTEXT_C_0, "mm"
147 , subjectAltNames
148 , challengePassword);
149 }
150
151 /**
152 * @brief Builds a DER-code pkcs#10 certificate request
153 *
154 * @param[in] pkcs10 pointer to a pkcs10_t struct
155 * @return DER-code pkcs10 request
156 */
157 static chunk_t
158 pkcs10_build_request(pkcs10_t *pkcs10, int signature_alg)
159 {
160 chunk_t key = pkcs10->public_key->get_encoding(pkcs10->public_key);
161
162 chunk_t keyInfo = asn1_wrap(ASN1_SEQUENCE, "cm",
163 asn1_algorithmIdentifier(OID_RSA_ENCRYPTION),
164 asn1_bitstring("m", key));
165
166 chunk_t cert_req_info = asn1_wrap(ASN1_SEQUENCE, "ccmm",
167 ASN1_INTEGER_0,
168 pkcs10->subject,
169 keyInfo,
170 build_req_info_attributes(pkcs10));
171
172 chunk_t signature = x509_build_signature(cert_req_info, signature_alg,
173 pkcs10->private_key, TRUE);
174
175 return asn1_wrap(ASN1_SEQUENCE, "mcm",
176 cert_req_info,
177 asn1_algorithmIdentifier(signature_alg),
178 signature);
179 }
180
181 /**
182 * @brief Creates a pkcs#10 certificate request object
183 *
184 * To create a certificate request, the RSA key and the
185 * names to be included as subject in the certificate request
186 * (e.g. commonName, organization) are needed. An optional challenge
187 * password or some subjectAltNames may be included.
188 *
189 * @param[in] key rsakey of type #rsakey_t
190 * @param[in] subject DER-coded subject distinguished name
191 * @param[in] challengePassword challenge password or chunk_empty
192 * @param[in] subjectAltNames linked list of subjectAltNames or NULL
193 * @return pointer to a #pkcs10_t object
194 */
195 pkcs10_t* pkcs10_build(private_key_t *private, public_key_t *public,
196 chunk_t subject, chunk_t challengePassword,
197 generalName_t *subjectAltNames, int signature_alg)
198 {
199 pkcs10_t *pkcs10 = malloc_thing(pkcs10_t);
200
201 pkcs10->subject = subject;
202 pkcs10->private_key = private;
203 pkcs10->public_key = public;
204 pkcs10->challengePassword = challengePassword;
205 pkcs10->subjectAltNames = subjectAltNames;
206
207 pkcs10->request = pkcs10_build_request(pkcs10, signature_alg);
208 return pkcs10;
209 }
210
211 /**
212 * @brief Frees the resources used by an #pkcs10_t object
213 *
214 * @param[in] pkcs10 #pkcs10_t to free
215 */
216 void
217 pkcs10_free(pkcs10_t *pkcs10)
218 {
219 if (pkcs10 != NULL)
220 {
221 free(pkcs10->request.ptr);
222 free(pkcs10);
223 }
224 }