diff options
Diffstat (limited to 'doc/chapters/tlsauthentication.inc')
-rw-r--r-- | doc/chapters/tlsauthentication.inc | 172 |
1 files changed, 171 insertions, 1 deletions
diff --git a/doc/chapters/tlsauthentication.inc b/doc/chapters/tlsauthentication.inc index 125d4eb6..4f9c4443 100644 --- a/doc/chapters/tlsauthentication.inc +++ b/doc/chapters/tlsauthentication.inc | |||
@@ -105,6 +105,7 @@ The rest consists of little new besides some additional memory cleanups. | |||
105 | 105 | ||
106 | The rather unexciting file loader can be found in the complete example @code{tlsauthentication.c}. | 106 | The rather unexciting file loader can be found in the complete example @code{tlsauthentication.c}. |
107 | 107 | ||
108 | |||
108 | @heading Remarks | 109 | @heading Remarks |
109 | @itemize @bullet | 110 | @itemize @bullet |
110 | @item | 111 | @item |
@@ -126,5 +127,174 @@ hardcode certificates in embedded devices. | |||
126 | The cryptographic facilities consume memory space and computing time. For this reason, websites usually consists | 127 | The cryptographic facilities consume memory space and computing time. For this reason, websites usually consists |
127 | both of uncritically @emph{HTTP} parts and secured @emph{HTTPS}. | 128 | both of uncritically @emph{HTTP} parts and secured @emph{HTTPS}. |
128 | 129 | ||
129 | |||
130 | @end itemize | 130 | @end itemize |
131 | |||
132 | |||
133 | @heading Client authentication | ||
134 | |||
135 | You can also use MHD to authenticate the client via SSL/TLS certificates | ||
136 | (as an alternative to using the password-based Basic or Digest authentication). | ||
137 | To do this, you will need to link your application against @emph{gnutls}. | ||
138 | For this, you first need to obtain the raw GnuTLS session handle from | ||
139 | @emph{MHD} using @code{MHD_get_connection_info}. | ||
140 | |||
141 | @verbatim | ||
142 | #include <gnutls/gnutls.h> | ||
143 | #include <gnutls/x509.h> | ||
144 | |||
145 | gnutls_session_t tls_session; | ||
146 | tls_session = MHD_get_connection_info (connection, | ||
147 | MHD_CONNECTION_INFO_GNUTLS_SESSION); | ||
148 | @end verbatim | ||
149 | |||
150 | You can then extract the client certificate: | ||
151 | |||
152 | @verbatim | ||
153 | /** | ||
154 | * Get the client's certificate | ||
155 | * | ||
156 | * @param tls_session the TLS session | ||
157 | * @return NULL if no valid client certificate could be found, a pointer | ||
158 | * to the certificate if found | ||
159 | */ | ||
160 | static gnutls_x509_crt_t | ||
161 | get_client_certificate (gnutls_session_t tls_session) | ||
162 | { | ||
163 | unsigned int listsize; | ||
164 | const gnutls_datum_t * pcert; | ||
165 | gnutls_certificate_status_t client_cert_status; | ||
166 | gnutls_x509_crt_t client_cert; | ||
167 | |||
168 | if (tls_session == NULL) | ||
169 | return NULL; | ||
170 | if (gnutls_certificate_verify_peers2(tls_session, | ||
171 | &client_cert_status)) | ||
172 | return NULL; | ||
173 | pcert = gnutls_certificate_get_peers(tls_session, | ||
174 | &listsize); | ||
175 | if ( (pcert == NULL) || | ||
176 | (listsize == 0)) | ||
177 | { | ||
178 | fprintf (stderr, | ||
179 | "Failed to retrieve client certificate chain\n"); | ||
180 | return NULL; | ||
181 | } | ||
182 | if (gnutls_x509_crt_init(&client_cert)) | ||
183 | { | ||
184 | fprintf (stderr, | ||
185 | "Failed to initialize client certificate\n"); | ||
186 | return NULL; | ||
187 | } | ||
188 | /* Note that by passing values between 0 and listsize here, you | ||
189 | can get access to the CA's certs */ | ||
190 | if (gnutls_x509_crt_import(client_cert, | ||
191 | &pcert[0], | ||
192 | GNUTLS_X509_FMT_DER)) | ||
193 | { | ||
194 | fprintf (stderr, | ||
195 | "Failed to import client certificate\n"); | ||
196 | gnutls_x509_crt_deinit(client_cert); | ||
197 | return NULL; | ||
198 | } | ||
199 | return client_cert; | ||
200 | } | ||
201 | @end verbatim | ||
202 | |||
203 | Using the client certificate, you can then get the client's distinguished name | ||
204 | and alternative names: | ||
205 | |||
206 | @verbatim | ||
207 | /** | ||
208 | * Get the distinguished name from the client's certificate | ||
209 | * | ||
210 | * @param client_cert the client certificate | ||
211 | * @return NULL if no dn or certificate could be found, a pointer | ||
212 | * to the dn if found | ||
213 | */ | ||
214 | char * | ||
215 | cert_auth_get_dn(gnutls_x509_crt_c client_cert) | ||
216 | { | ||
217 | char* buf; | ||
218 | size_t lbuf; | ||
219 | |||
220 | lbuf = 0; | ||
221 | gnutls_x509_crt_get_dn(client_cert, NULL, &lbuf); | ||
222 | buf = malloc(lbuf); | ||
223 | if (buf == NULL) | ||
224 | { | ||
225 | fprintf (stderr, | ||
226 | "Failed to allocate memory for certificate dn\n"); | ||
227 | return NULL; | ||
228 | } | ||
229 | gnutls_x509_crt_get_dn(client_cert, buf, &lbuf); | ||
230 | return buf; | ||
231 | } | ||
232 | |||
233 | |||
234 | /** | ||
235 | * Get the alternative name of specified type from the client's certificate | ||
236 | * | ||
237 | * @param client_cert the client certificate | ||
238 | * @param nametype The requested name type | ||
239 | * @param index The position of the alternative name if multiple names are | ||
240 | * matching the requested type, 0 for the first matching name | ||
241 | * @return NULL if no matching alternative name could be found, a pointer | ||
242 | * to the alternative name if found | ||
243 | */ | ||
244 | char * | ||
245 | MHD_cert_auth_get_alt_name(gnutls_x509_crt_t client_cert, | ||
246 | int nametype, | ||
247 | unsigned int index) | ||
248 | { | ||
249 | char* buf; | ||
250 | size_t lbuf; | ||
251 | unsigned int seq; | ||
252 | unsigned int subseq; | ||
253 | unsigned int type; | ||
254 | int result; | ||
255 | |||
256 | subseq = 0; | ||
257 | for (seq=0;;seq++) | ||
258 | { | ||
259 | lbuf = 0; | ||
260 | result = gnutls_x509_crt_get_subject_alt_name2(client_cert, seq, NULL, &lbuf, | ||
261 | &type, NULL); | ||
262 | if (result == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) | ||
263 | return NULL; | ||
264 | if (nametype != (int) type) | ||
265 | continue; | ||
266 | if (subseq == index) | ||
267 | break; | ||
268 | subseq++; | ||
269 | } | ||
270 | buf = malloc(lbuf); | ||
271 | if (buf == NULL) | ||
272 | { | ||
273 | fprintf (stderr, | ||
274 | "Failed to allocate memory for certificate alt name\n"); | ||
275 | return NULL; | ||
276 | } | ||
277 | result = gnutls_x509_crt_get_subject_alt_name2(client_cert, | ||
278 | seq, | ||
279 | buf, | ||
280 | &lbuf, | ||
281 | NULL, NULL); | ||
282 | if (result != nametype) | ||
283 | { | ||
284 | fprintf (stderr, | ||
285 | "Unexpected return value from gnutls: %d\n", | ||
286 | result); | ||
287 | free (buf); | ||
288 | return NULL; | ||
289 | } | ||
290 | return buf; | ||
291 | } | ||
292 | @end verbatim | ||
293 | |||
294 | Finally, you should release the memory associated with the client | ||
295 | certificate: | ||
296 | |||
297 | @verbatim | ||
298 | gnutls_x509_crt_deinit (client_cert); | ||
299 | @end verbatim | ||
300 | |||