1 /*
2  * Copyright 2001-2003 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 #include <stdio.h>
7 #include <string.h>
8 #include "lber.h"
9 #include "ldap.h"
10 #include "ldap-int.h"
11 #include <sys/types.h>
12 #include <strings.h>
13 #include "sec.h"
14 
15 /* text is the challenge, key is the password, digest is an allocated
16    buffer (min 16 chars) which will contain the resulting digest */
hmac_md5(unsigned char * text,int text_len,unsigned char * key,int key_len,unsigned char * digest)17 void hmac_md5(unsigned char *text, int text_len, unsigned char *key,
18 	int key_len, unsigned char *digest)
19 {
20 	MD5_CTX context;
21 	unsigned char k_ipad[65];
22 	unsigned char k_opad[65];
23 	unsigned char tk[16];
24 	int i;
25 
26 	if (key_len > 64){
27 		MD5_CTX tctx;
28 
29 		(void) MD5Init(&tctx);
30 		(void) MD5Update(&tctx, key, key_len);
31 		(void) MD5Final(tk, &tctx);
32 		key = tk;
33 		key_len = 16;
34 	}
35 
36 	bzero(k_ipad, sizeof (k_ipad));
37 	bzero(k_opad, sizeof (k_opad));
38 	bcopy(key, k_ipad, key_len);
39 	bcopy(key, k_opad, key_len);
40 
41 	for (i=0; i<64; i++){
42 		k_ipad[i] ^= 0x36;
43 		k_opad[i] ^= 0x5c;
44 	}
45 
46 	/* Perform inner MD5 */
47 	(void) MD5Init(&context);
48 	(void) MD5Update(&context, k_ipad, 64);
49 	(void) MD5Update(&context, text, text_len);
50 	(void) MD5Final(digest, &context);
51 
52 	/* Perform outer MD5 */
53 	(void) MD5Init(&context);
54 	(void) MD5Update(&context, k_opad, 64);
55 	(void) MD5Update(&context, digest, 16);
56 
57 	(void) MD5Final(digest, &context);
58 
59 	return;
60 }
61 
ldap_sasl_cram_md5_bind_s(LDAP * ld,char * dn,struct berval * cred,LDAPControl ** serverctrls,LDAPControl ** clientctrls)62 int ldap_sasl_cram_md5_bind_s(
63 	LDAP *ld,
64 	char *dn,
65 	struct berval *cred,
66 	LDAPControl **serverctrls,
67 	LDAPControl **clientctrls )
68 {
69 	int res;
70 	struct berval *challenge = NULL;
71 	struct berval resp;
72 	unsigned char digest[16];
73 	char *theHDigest;
74 
75 	if (dn == NULL){
76 		return (LDAP_PARAM_ERROR);
77 	}
78 
79 	bzero(digest, sizeof (digest));
80 
81 	if ((res = ldap_sasl_bind_s(ld, NULL, LDAP_SASL_CRAM_MD5, NULL, serverctrls, clientctrls, &challenge))
82 		!= LDAP_SASL_BIND_IN_PROGRESS){
83 		return (res);
84 	}
85 	if (challenge == NULL){
86 		return (LDAP_PARAM_ERROR);
87 	}
88 
89 	LDAPDebug (LDAP_DEBUG_TRACE, "SASL challenge: %s\n", challenge->bv_val, 0, 0);
90 
91 	hmac_md5((unsigned char *)challenge->bv_val, challenge->bv_len,
92 					 (unsigned char *)cred->bv_val, cred->bv_len,  digest);
93 	ber_bvfree(challenge);
94 	challenge = NULL;
95 
96 	theHDigest = hexa_print(digest, 16);
97 	if (theHDigest == NULL){
98 		return (LDAP_NO_MEMORY);
99 	}
100 
101 	resp.bv_len = (strlen(dn) + 32 + 1);
102 	if ((resp.bv_val = (char *)malloc(resp.bv_len+1)) == NULL) {
103 		return(LDAP_NO_MEMORY);
104 	}
105 
106 	sprintf(resp.bv_val, "%s %s", dn, theHDigest);
107 	free(theHDigest);
108 
109 	LDAPDebug (LDAP_DEBUG_TRACE, "SASL response: %s\n", resp.bv_val, 0, 0);
110 	res = ldap_sasl_bind_s(ld, NULL, LDAP_SASL_CRAM_MD5, &resp, serverctrls, clientctrls, &challenge);
111 
112 	free(resp.bv_val);
113 	return (res);
114 }
115