1 /*
2  * Copyright (c) 2008-2013 Zmanda, Inc.  All Rights Reserved.
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
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) 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 MERCHANTABILITY
11  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
17  *
18  * Contact information: Zmanda Inc., 465 S. Mathilda Ave., Suite 300
19  * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
20  */
21 
22 
23 #ifdef HAVE_CONFIG_H
24 /* use a relative path here to avoid conflicting with Perl's config.h. */
25 #include "../config/config.h"
26 #endif
27 #ifdef HAVE_REGEX_H
28 #include <sys/types.h>
29 #include <regex.h>
30 #endif
31 #ifdef HAVE_AMANDA_H
32 #include "amanda.h"
33 #endif
34 
35 #include <glib.h>
36 #include <openssl/hmac.h>
37 #include <openssl/sha.h>
38 #include <openssl/md5.h>
39 #include <openssl/bio.h>
40 #include <openssl/evp.h>
41 #include <openssl/bn.h>
42 #include "s3-util.h"
43 
44 #ifdef HAVE_REGEX_H
45 int
s3_regexec_wrap(regex_t * regex,const char * str,size_t nmatch,regmatch_t pmatch[],int eflags)46 s3_regexec_wrap(regex_t *regex,
47            const char *str,
48            size_t nmatch,
49            regmatch_t pmatch[],
50            int eflags)
51 {
52     char *message;
53     int size;
54     int reg_result;
55 
56     reg_result = regexec(regex, str, nmatch, pmatch, eflags);
57     if (reg_result != 0 && reg_result != REG_NOMATCH) {
58         size = regerror(reg_result, regex, NULL, 0);
59         message = g_malloc(size);
60         regerror(reg_result, regex, message, size);
61 
62         /* this is programmer error (bad regexp), so just log
63          * and abort().  There's no good way to signal a
64          * permanaent error from interpret_response. */
65         g_critical(_("Regex error: %s"), message);
66     }
67 
68     return reg_result;
69 }
70 #else
71 
72 int
s3_regexec_wrap(regex_t * regex,const char * str,size_t nmatch,regmatch_t pmatch[],int eflags)73 s3_regexec_wrap(regex_t *regex,
74            const char *str,
75            size_t nmatch,
76            regmatch_t pmatch[],
77            int eflags)
78 {
79     GMatchInfo *match_info;
80     int ret = REG_NOERROR;
81     guint i;
82 
83     g_assert(regex && *regex);
84     g_regex_match(*regex, str, eflags, &match_info);
85     if (g_match_info_matches(match_info)) {
86         g_assert(g_match_info_get_match_count(match_info) <= (glong) nmatch);
87         for (i = 0; i < nmatch; i++) {
88             pmatch[i].rm_eo = pmatch[i].rm_so = -1;
89             g_match_info_fetch_pos(match_info, i, &pmatch[i].rm_so, &pmatch[i].rm_eo);
90         }
91     } else {
92         ret = REG_NOMATCH;
93     }
94     g_match_info_free(match_info);
95     return ret;
96 }
97 #endif
98 
99 #ifndef HAVE_AMANDA_H
100 char*
find_regex_substring(const char * base_string,const regmatch_t match)101 find_regex_substring(const char* base_string, const regmatch_t match)
102 {
103     g_assert(match.rm_eo >= match.rm_so);
104     return g_strndup(base_string+match.rm_so, match.rm_eo - match.rm_so);
105 }
106 #endif
107 
108 gchar*
s3_base64_encode(const GByteArray * to_enc)109 s3_base64_encode(const GByteArray *to_enc) {
110     BIO *bio_b64 = NULL, *bio_buff = NULL;
111     long bio_b64_len;
112     char *bio_b64_data = NULL, *ret = NULL;
113     if (!to_enc) return NULL;
114 
115     /* Initialize base64 encoding filter */
116     bio_b64 = BIO_new(BIO_f_base64());
117     g_assert(bio_b64);
118     BIO_set_flags(bio_b64, BIO_FLAGS_BASE64_NO_NL);
119 
120     /* Initialize memory buffer for the base64 encoding */
121     bio_buff = BIO_new(BIO_s_mem());
122     g_assert(bio_buff);
123     bio_buff = BIO_push(bio_b64, bio_buff);
124 
125     /* Write the MD5 hash into the buffer to encode it in base64 */
126     BIO_write(bio_buff, to_enc->data, to_enc->len);
127     /* BIO_flush is a macro and GCC 4.1.2 complains without this cast*/
128     (void) BIO_flush(bio_buff);
129 
130     /* Pull out the base64 encoding of the MD5 hash */
131     bio_b64_len = BIO_get_mem_data(bio_buff, &bio_b64_data);
132     g_assert(bio_b64_data);
133     ret = g_strndup(bio_b64_data, bio_b64_len);
134 
135     /* If bio_b64 is freed separately, freeing bio_buff will
136      * invalidly free memory and potentially segfault.
137      */
138     BIO_free_all(bio_buff);
139     return ret;
140 }
141 
142 gchar*
s3_hex_encode(const GByteArray * to_enc)143 s3_hex_encode(const GByteArray *to_enc)  {
144     guint i;
145     gchar *ret = NULL, table[] = "0123456789abcdef";
146     if (!to_enc) return NULL;
147 
148     ret = g_new(gchar, to_enc->len*2 + 1);
149     for (i = 0; i < to_enc->len; i++) {
150         /* most significant 4 bits */
151         ret[i*2] = table[to_enc->data[i] >> 4];
152         /* least significant 4 bits */
153         ret[i*2 + 1] = table[to_enc->data[i] & 0xf];
154     }
155     ret[to_enc->len*2] = '\0';
156 
157     return ret;
158 }
159 
160 GByteArray*
s3_compute_md5_hash(const GByteArray * to_hash)161 s3_compute_md5_hash(const GByteArray *to_hash) {
162     MD5_CTX md5_ctx;
163     GByteArray *ret;
164     if (!to_hash) return NULL;
165 
166     ret = g_byte_array_sized_new(S3_MD5_HASH_BYTE_LEN);
167     g_byte_array_set_size(ret, S3_MD5_HASH_BYTE_LEN);
168 
169     MD5_Init(&md5_ctx);
170     MD5_Update(&md5_ctx, to_hash->data, to_hash->len);
171     MD5_Final(ret->data, &md5_ctx);
172 
173     return ret;
174 }
175 
176 char *
s3_compute_sha256_hash_ba(const GByteArray * to_hash)177 s3_compute_sha256_hash_ba(
178     const GByteArray *to_hash)
179 {
180     return s3_compute_sha256_hash(to_hash->data, to_hash->len);
181 }
182 
183 char *
s3_compute_sha256_hash(const unsigned char * to_hash,int len)184 s3_compute_sha256_hash(
185     const unsigned char *to_hash,
186     int len)
187 {
188     unsigned char hash[SHA256_DIGEST_LENGTH];
189     char *ret = malloc(64);
190     int i;
191 
192     SHA256_CTX sha256;
193     SHA256_Init(&sha256);
194     SHA256_Update(&sha256, to_hash, len);
195     SHA256_Final(hash, &sha256);
196     for (i = 0; i < SHA256_DIGEST_LENGTH; i++) {
197         sprintf(ret + (i * 2), "%02x", hash[i]);
198     }
199     ret[64] = 0;
200     return ret;
201 }
202 
203 char *
s3_uri_encode(const char * s,gboolean encodeSlash)204 s3_uri_encode(
205     const char *s,
206     gboolean encodeSlash)
207 {
208     GString *ret = g_string_new("");
209     int i;
210     int len_s = strlen(s);
211 
212     for (i = 0; i < len_s; i++) {
213 	unsigned char ch = s[i];
214 	if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9') || ch == '_' || ch == '-' || ch == '~' || ch == '.') {
215 	    g_string_append_c(ret, ch);
216 	} else if (ch == '/') {
217 	    if (encodeSlash) {
218 		g_string_append(ret, "%2F");
219 	    } else {
220 		g_string_append_c(ret, ch);
221 	    }
222 	} else {
223 	    g_string_append_printf(ret, "%02x", ch);
224 	}
225     }
226     return g_string_free(ret, FALSE);
227 }
228 
229 unsigned char *
EncodeHMACSHA256(unsigned char * key,int keylen,const char * data,int datalen)230 EncodeHMACSHA256(
231     unsigned char* key,
232     int keylen,
233     const char* data,
234     int datalen)
235 {
236     unsigned char *hmachash = malloc(32);
237     const unsigned char *datatohash = (unsigned char *)data;
238     unsigned char tk[SHA256_DIGEST_LENGTH];
239 
240     // Initialise HMACh
241     HMAC_CTX HMAC;
242     unsigned int hmaclength = 32;
243     memset(hmachash, 0, hmaclength);
244 
245     if (keylen > 64 ) {
246 	SHA256(key, keylen, tk);
247 	key    = tk;
248 	keylen = SHA256_DIGEST_LENGTH;
249     }
250 
251     // Digest the key and message using SHA256
252     HMAC_CTX_init(&HMAC);
253     HMAC_Init_ex(&HMAC, key, keylen, EVP_sha256(),NULL);
254     HMAC_Update(&HMAC, datatohash, datalen);
255     HMAC_Final(&HMAC, hmachash, &hmaclength);
256     HMAC_CTX_cleanup(&HMAC);
257 
258     return hmachash;
259 }
260 
261 unsigned char *
s3_tohex(unsigned char * s,int len_s)262 s3_tohex(
263     unsigned char *s,
264     int len_s)
265 {
266     unsigned char *r = malloc(len_s*2+1);
267     unsigned char *t = r;
268     int   i;
269     gchar table[] = "0123456789abcdef";
270 
271     for (i = 0; i < len_s; i++) {
272 	/* most significant 4 bits */
273 	*t++ = table[s[i] >> 4];
274 	/* least significant 4 bits */
275 	*t++ = table[s[i] & 0xf];
276     }
277     *t = '\0';
278     return r;
279 }
280 
281