1 /*
2 * Copyright (c) 2000
3 * Traakan, Inc., Los Altos, CA
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice unmodified, this list of conditions, and the following
11 * disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 /*
30 * Project: NDMJOB
31 * Ident: $Id: $
32 *
33 * Description:
34 *
35 * MD5 authentication support
36 ****************************************************************
37 * Both sides share a secret in the form of a clear-text
38 * password. One side generates a challenge (64-bytes)
39 * and conveys it to the other. The other side then
40 * uses the challenge, the clear-text password, and
41 * the NDMP rules for MD5, and generates a digest.
42 * The digest is returned as proof that both sides
43 * share the same secret clear-text password.
44 *
45 * The NDMP rules for MD5 are implemented in ndmmd5_digest().
46 * It amounts to positioning the clear-text password and challenge
47 * into a "message" buffer, then applying the MD5 algorithm.
48 *
49 * ndmmd5_generate_challenge() generates a challenge[]
50 * using conventional random number routines.
51 *
52 * ndmmd5_ok_digest() takes a locally known challenge[]
53 * and clear-text password, a remotely generated
54 * digest[], and determines if everything is correct.
55 *
56 * Using MD5 prevents clear-text passwords from being conveyed
57 * over the network. However, it compels both sides to maintain
58 * clear-text passwords in a secure fashion, which is difficult
59 * to say the least. Because the NDMP MD5 rules must be followed
60 * to digest() the password, it's impractical to consider
61 * an external authentication authority.
62 *
63 * Credits to Rajiv of NetApp for helping with MD5 stuff.
64 */
65
66
67 #include "ndmlib.h"
68 #include "md5.h"
69
70
ndmmd5_generate_challenge(char challenge[NDMP_MD5_CHALLENGE_LENGTH])71 int ndmmd5_generate_challenge(char challenge[NDMP_MD5_CHALLENGE_LENGTH])
72 {
73 int i;
74
75 NDMOS_MACRO_SRAND();
76
77 for (i = 0; i < NDMP_MD5_CHALLENGE_LENGTH; i++) {
78 challenge[i] = NDMOS_MACRO_RAND() >> (i & 7);
79 }
80
81 return 0;
82 }
83
84
ndmmd5_ok_digest(char challenge[NDMP_MD5_CHALLENGE_LENGTH],char * clear_text_password,char digest[NDMP_MD5_DIGEST_LENGTH])85 int ndmmd5_ok_digest(char challenge[NDMP_MD5_CHALLENGE_LENGTH],
86 char* clear_text_password,
87 char digest[NDMP_MD5_DIGEST_LENGTH])
88 {
89 char my_digest[16];
90 int i;
91
92 ndmmd5_digest(challenge, clear_text_password, my_digest);
93
94 for (i = 0; i < NDMP_MD5_DIGEST_LENGTH; i++)
95 if (digest[i] != my_digest[i]) return 0; /* Invalid */
96
97 return 1; /* OK */
98 }
99
100
ndmmd5_digest(char challenge[NDMP_MD5_CHALLENGE_LENGTH],char * clear_text_password,char digest[NDMP_MD5_DIGEST_LENGTH])101 int ndmmd5_digest(char challenge[NDMP_MD5_CHALLENGE_LENGTH],
102 char* clear_text_password,
103 char digest[NDMP_MD5_DIGEST_LENGTH])
104 {
105 int pwlength = strlen(clear_text_password);
106 struct MD5Context mdContext;
107 unsigned char message[128];
108
109 /*
110 * The spec describes the construction of the 128 byte
111 * "message" (probably MD5-speak). It is described as:
112 *
113 * PASSWORD PADDING CHALLENGE PADDING PASSWORD
114 *
115 * Each PADDING is defined as zeros of length 64 minus pwlen.
116 *
117 * A pwlen of over 32 would result in not all fields
118 * fitting. This begs a question of the order elements
119 * are inserted into the message[]. You get a different
120 * message[] if you insert the PASSWORD(s) before
121 * the CHALLENGE than you get the other way around.
122 *
123 * A pwlen of over 64 would result in PADDING of negative
124 * length, which could cause crash boom bang.
125 *
126 * The resolution of this vaguery implemented here is to
127 * only use the first 32 bytes of the password. All
128 * fields fit. Order dependencies are avoided.
129 *
130 * Final resolution is pending.
131 */
132 if (pwlength > 32) pwlength = 32;
133
134 /*
135 * Compose the 128-byte buffer according to NDMP rules
136 */
137 NDMOS_API_BZERO(message, sizeof message);
138 NDMOS_API_BCOPY(clear_text_password, &message[0], pwlength);
139 NDMOS_API_BCOPY(clear_text_password, &message[128 - pwlength], pwlength);
140 NDMOS_API_BCOPY(challenge, &message[64 - pwlength], 64);
141
142 /*
143 * Grind it up, ala MD5
144 */
145 MD5Init(&mdContext);
146 MD5Update(&mdContext, message, 128);
147 MD5Final((unsigned char*)digest, &mdContext);
148
149 /*
150 * ding! done
151 */
152 return 0;
153 }
154