6bebaca5a3ef7b1bbaa8aca96983df0448fe0c94
[people/xl0/gpxe.git] / src / crypto / chap.c
1 /*
2  * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or any later version.
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
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18
19 #include <stddef.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <errno.h>
23 #include <assert.h>
24 #include <gpxe/crypto.h>
25 #include <gpxe/chap.h>
26
27 /** @file
28  *
29  * CHAP protocol
30  *
31  */
32
33 /**
34  * Initialise CHAP challenge/response
35  *
36  * @v chap              CHAP challenge/response
37  * @v digest            Digest algorithm to use
38  * @ret rc              Return status code
39  *
40  * Initialises a CHAP challenge/response structure.  This routine
41  * allocates memory, and so may fail.  The allocated memory must
42  * eventually be freed by a call to chap_finish().
43  */
44 int chap_init ( struct chap_challenge *chap,
45                 struct digest_algorithm *digest ) {
46         size_t state_len;
47         void *state;
48
49         assert ( chap->digest == NULL );
50         assert ( chap->digest_context == NULL );
51         assert ( chap->response == NULL );
52
53         DBG ( "CHAP %p initialising with %s digest\n", chap, digest->name );
54
55         state_len = ( digest->context_len + digest->digest_len );
56         state = malloc ( state_len );
57         if ( ! state ) {
58                 DBG ( "CHAP %p could not allocate %d bytes for state\n",
59                       chap, state_len );
60                 return -ENOMEM;
61         }
62         
63         chap->digest = digest;
64         chap->digest_context = state;
65         chap->response = ( state + digest->context_len );
66         chap->response_len = digest->digest_len;
67         chap->digest->init ( chap->digest_context );
68         return 0;
69 }
70
71 /**
72  * Add data to the CHAP challenge
73  *
74  * @v chap              CHAP challenge/response
75  * @v data              Data to add
76  * @v len               Length of data to add
77  */
78 void chap_update ( struct chap_challenge *chap, const void *data,
79                    size_t len ) {
80         assert ( chap->digest != NULL );
81         assert ( chap->digest_context != NULL );
82
83         if ( ! chap->digest )
84                 return;
85
86         chap->digest->update ( chap->digest_context, data, len );
87 }
88
89 /**
90  * Respond to the CHAP challenge
91  *
92  * @v chap              CHAP challenge/response
93  *
94  * Calculates the final CHAP response value, and places it in @c
95  * chap->response, with a length of @c chap->response_len.
96  */
97 void chap_respond ( struct chap_challenge *chap ) {
98         assert ( chap->digest != NULL );
99         assert ( chap->digest_context != NULL );
100         assert ( chap->response != NULL );
101
102         DBG ( "CHAP %p responding to challenge\n", chap );
103
104         if ( ! chap->digest )
105                 return;
106
107         chap->digest->finish ( chap->digest_context, chap->response );
108 }
109
110 /**
111  * Free resources used by a CHAP challenge/response
112  *
113  * @v chap              CHAP challenge/response
114  */
115 void chap_finish ( struct chap_challenge *chap ) {
116         void *state = chap->digest_context;
117
118         DBG ( "CHAP %p finished\n", chap );
119
120         free ( state );
121         memset ( chap, 0, sizeof ( *chap ) );
122 }