2 * Copyright (c) 2010 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Portions Copyright (c) 2010 Apple Inc. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the Institute nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 #include <sys/types.h>
39 #include <CommonCrypto/CommonDigest.h>
40 #include <CommonCrypto/CommonHMAC.h>
43 #include "heim-auth.h"
47 heim_generate_challenge(const char *hostname
)
49 char host
[MAXHOSTNAMELEN
], *str
= NULL
;
52 if (hostname
== NULL
) {
53 if (gethostname(host
, sizeof(host
)))
61 asprintf(&str
, "<%lu%lu@%s>", (unsigned long)t
,
62 (unsigned long)num
, hostname
);
68 heim_apop_create(const char *challenge
, const char *password
)
71 uint8_t hash
[CC_MD5_DIGEST_LENGTH
];
75 CC_MD5_Update(&ctx
, challenge
, strlen(challenge
));
76 CC_MD5_Update(&ctx
, password
, strlen(password
));
78 CC_MD5_Final(hash
, &ctx
);
80 hex_encode(hash
, sizeof(hash
), &str
);
88 heim_apop_verify(const char *challenge
, const char *password
, const char *response
)
93 str
= heim_apop_create(challenge
, password
);
97 res
= (strcasecmp(str
, response
) != 0);
101 return HNTLM_ERR_INVALID_APOP
;
105 struct heim_cram_md5
{
112 heim_cram_md5_export(const char *password
, heim_CRAM_MD5_STATE
*state
)
114 size_t keylen
= strlen(password
);
115 uint8_t key
[CC_MD5_BLOCK_BYTES
];
116 uint8_t pad
[CC_MD5_BLOCK_BYTES
];
117 struct heim_cram_md5 ctx
;
120 memset(&ctx
, 0, sizeof(ctx
));
122 if (keylen
> CC_MD5_BLOCK_BYTES
) {
123 CC_MD5(password
, keylen
, key
);
124 keylen
= sizeof(keylen
);
126 memcpy(key
, password
, keylen
);
129 memset(pad
, 0x36, sizeof(pad
));
130 for (n
= 0; n
< keylen
; n
++)
133 CC_MD5_Init(&ctx
.ipad
);
134 CC_MD5_Init(&ctx
.opad
);
136 CC_MD5_Update(&ctx
.ipad
, pad
, sizeof(pad
));
138 memset(pad
, 0x5c, sizeof(pad
));
139 for (n
= 0; n
< keylen
; n
++)
142 CC_MD5_Update(&ctx
.opad
, pad
, sizeof(pad
));
144 memset(pad
, 0, sizeof(pad
));
145 memset(key
, 0, sizeof(key
));
147 state
->istate
[0] = htonl(ctx
.ipad
.A
);
148 state
->istate
[1] = htonl(ctx
.ipad
.B
);
149 state
->istate
[2] = htonl(ctx
.ipad
.C
);
150 state
->istate
[3] = htonl(ctx
.ipad
.D
);
152 state
->ostate
[0] = htonl(ctx
.opad
.A
);
153 state
->ostate
[1] = htonl(ctx
.opad
.B
);
154 state
->ostate
[2] = htonl(ctx
.opad
.C
);
155 state
->ostate
[3] = htonl(ctx
.opad
.D
);
157 memset(&ctx
, 0, sizeof(ctx
));
162 heim_cram_md5_import(void *data
, size_t len
)
164 heim_CRAM_MD5_STATE state
;
168 if (len
!= sizeof(state
))
171 ctx
= calloc(1, sizeof(*ctx
));
175 memcpy(&state
, data
, sizeof(state
));
177 ctx
->ipad
.A
= ntohl(state
.istate
[0]);
178 ctx
->ipad
.B
= ntohl(state
.istate
[1]);
179 ctx
->ipad
.C
= ntohl(state
.istate
[2]);
180 ctx
->ipad
.D
= ntohl(state
.istate
[3]);
182 ctx
->opad
.A
= ntohl(state
.ostate
[0]);
183 ctx
->opad
.B
= ntohl(state
.ostate
[1]);
184 ctx
->opad
.C
= ntohl(state
.ostate
[2]);
185 ctx
->opad
.D
= ntohl(state
.ostate
[3]);
187 ctx
->ipad
.Nl
= ctx
->opad
.Nl
= 512;
188 ctx
->ipad
.Nh
= ctx
->opad
.Nh
= 0;
189 ctx
->ipad
.num
= ctx
->opad
.num
= 0;
195 heim_cram_md5_verify_ctx(heim_cram_md5 ctx
, const char *challenge
, const char *response
)
197 uint8_t hash
[CC_MD5_DIGEST_LENGTH
];
201 CC_MD5_Update(&ctx
->ipad
, challenge
, strlen(challenge
));
202 CC_MD5_Final(hash
, &ctx
->ipad
);
204 CC_MD5_Update(&ctx
->opad
, hash
, sizeof(hash
));
205 CC_MD5_Final(hash
, &ctx
->opad
);
207 hex_encode(hash
, sizeof(hash
), &str
);
211 res
= (strcasecmp(str
, response
) != 0);
215 return HNTLM_ERR_INVALID_CRAM_MD5
;
220 heim_cram_md5_free(heim_cram_md5 ctx
)
222 memset(ctx
, 0, sizeof(*ctx
));
228 heim_cram_md5_create(const char *challenge
, const char *password
)
231 uint8_t hash
[CC_MD5_DIGEST_LENGTH
];
234 CCHmacInit(&ctx
, kCCHmacAlgMD5
, password
, strlen(password
));
235 CCHmacUpdate(&ctx
, challenge
, strlen(challenge
));
236 CCHmacFinal(&ctx
, hash
);
238 memset(&ctx
, 0, sizeof(ctx
));
240 hex_encode(hash
, sizeof(hash
), &str
);
248 heim_cram_md5_verify(const char *challenge
, const char *password
, const char *response
)
253 str
= heim_cram_md5_create(challenge
, password
);
257 res
= (strcasecmp(str
, response
) != 0);
261 return HNTLM_ERR_INVALID_CRAM_MD5
;