Merge nixio 0.2
[project/luci.git] / libs / nixio / src / tls-crypto.c
1 /*
2  * nixio - Linux I/O library for lua
3  *
4  *   Copyright (C) 2009 Steven Barth <steven@midlink.org>
5  *
6  *  Licensed under the Apache License, Version 2.0 (the "License");
7  *  you may not use this file except in compliance with the License.
8  *  You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an "AS IS" BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License.
17  */
18
19 #include "nixio-tls.h"
20 #include <string.h>
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <unistd.h>
24
25 static char nixio__bin2hex[] = {
26 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
27 };
28
29 static int nixio_crypto_hash__init(lua_State *L, int hmac) {
30         const char *type = luaL_checkstring(L, 1);
31         nixio_hash *hash = lua_newuserdata(L, sizeof(nixio_hash));
32
33         if (!strcmp(type, "md5")) {
34                 hash->type = NIXIO_HASH_MD5;
35                 hash->digest_size = MD5_DIGEST_LENGTH;
36                 hash->block_size = 64;
37                 hash->ctx = malloc(sizeof(MD5_CTX));
38                 if (!hash->ctx) {
39                         return luaL_error(L, NIXIO_OOM);
40                 }
41                 MD5_Init((MD5_CTX*)hash->ctx);
42                 hash->init = (nixio_hash_initcb)MD5_Init;
43                 hash->update = (nixio_hash_updatecb)MD5_Update;
44                 hash->final = (nixio_hash_finalcb)MD5_Final;
45         } else if (!strcmp(type, "sha1")) {
46                 hash->type = NIXIO_HASH_SHA1;
47                 hash->digest_size = SHA_DIGEST_LENGTH;
48                 hash->block_size = 64;
49                 hash->ctx = malloc(sizeof(SHA_CTX));
50                 if (!hash->ctx) {
51                         return luaL_error(L, NIXIO_OOM);
52                 }
53                 SHA1_Init((SHA_CTX*)hash->ctx);
54                 hash->init = (nixio_hash_initcb)SHA1_Init;
55                 hash->update = (nixio_hash_updatecb)SHA1_Update;
56                 hash->final = (nixio_hash_finalcb)SHA1_Final;
57         } else {
58                 luaL_argerror(L, 1, "supported values: md5, sha1");
59         }
60
61         luaL_getmetatable(L, NIXIO_CRYPTO_HASH_META);
62         lua_setmetatable(L, -2);
63
64         if (hmac) {
65                 const char *key = luaL_checklstring(L, 2, &hash->key_size);
66                 if (hash->key_size > hash->block_size) {
67                         hash->update(hash->ctx, key, hash->key_size);
68                         hash->final(hash->digest, hash->ctx);
69                         hash->init(hash->ctx);
70                         hash->key_size = hash->digest_size;
71                         memcpy(hash->key, hash->digest, hash->key_size);
72                 } else {
73                         memcpy(hash->key, key, hash->key_size);
74                 }
75
76                 unsigned char pad[NIXIO_CRYPTO_BLOCK_SIZE];
77                 for (uint i = 0; i < hash->block_size; i++) {
78                         pad[i] = (i < hash->key_size) ? (0x36 ^ hash->key[i]) : 0x36;
79                 }
80                 hash->update(hash->ctx, pad, hash->block_size);
81                 hash->type |= NIXIO_HMAC_BIT;
82         }
83
84         return 1;
85 }
86
87 static int nixio_crypto_hash(lua_State *L) {
88         return nixio_crypto_hash__init(L, 0);
89 }
90
91 static int nixio_crypto_hmac(lua_State *L) {
92         return nixio_crypto_hash__init(L, 1);
93 }
94
95 static int nixio_crypto_hash_update(lua_State *L) {
96         nixio_hash *hash = luaL_checkudata(L, 1, NIXIO_CRYPTO_HASH_META);
97         if (hash->type) {
98                 size_t len;
99                 const char *chunk = luaL_checklstring(L, 2, &len);
100                 hash->update(hash->ctx, chunk, len);
101                 lua_pushvalue(L, 1);
102                 return 1;
103         } else {
104                 return luaL_error(L, "Tried to update finalized hash object.");
105         }
106 }
107
108 static int nixio_crypto_hash_final(lua_State *L) {
109         nixio_hash *hash = luaL_checkudata(L, 1, NIXIO_CRYPTO_HASH_META);
110         if (hash->type & NIXIO_HMAC_BIT) {
111                 hash->final(hash->digest, hash->ctx);
112                 hash->init(hash->ctx);
113
114                 unsigned char pad[NIXIO_CRYPTO_BLOCK_SIZE];
115                 for (uint i = 0; i < hash->block_size; i++) {
116                         pad[i] = (i < hash->key_size) ? (0x5c ^ hash->key[i]) : 0x5c;
117                 }
118
119                 hash->update(hash->ctx, pad, hash->block_size);
120                 hash->update(hash->ctx, hash->digest, hash->digest_size);
121         }
122
123         if (hash->type) {
124                 hash->type = NIXIO_HASH_NONE;
125                 hash->final(hash->digest, hash->ctx);
126                 free(hash->ctx);
127         }
128
129         char hashdigest[NIXIO_DIGEST_SIZE*2];
130         for (uint i=0; i < hash->digest_size; i++) {
131                 hashdigest[2*i]   = nixio__bin2hex[(hash->digest[i] & 0xf0) >> 4];
132                 hashdigest[2*i+1] = nixio__bin2hex[(hash->digest[i] & 0x0f)];
133         }
134
135         lua_pushlstring(L, hashdigest, hash->digest_size * 2);
136         memcpy(hashdigest, hash->digest, hash->digest_size);
137         lua_pushlstring(L, hashdigest, hash->digest_size);
138
139         return 2;
140 }
141
142 static int nixio_crypto_hash__gc(lua_State *L) {
143         nixio_hash *hash = luaL_checkudata(L, 1, NIXIO_CRYPTO_HASH_META);
144         if (hash->type) {
145                 hash->final(hash->digest, hash->ctx);
146                 free(hash->ctx);
147                 hash->type = NIXIO_HASH_NONE;
148         }
149         return 0;
150 }
151
152 static int nixio_crypto_hash__tostring(lua_State *L) {
153         nixio_hash *hash = luaL_checkudata(L, 1, NIXIO_CRYPTO_HASH_META);
154         lua_pushfstring(L, "nixio hash object: %p", hash);
155         return 1;
156 }
157
158
159 /* module table */
160 static const luaL_reg R[] = {
161         {"hash",                nixio_crypto_hash},
162         {"hmac",                nixio_crypto_hmac},
163         {NULL,                  NULL}
164 };
165
166 /* hash table */
167 static const luaL_reg M[] = {
168         {"update",              nixio_crypto_hash_update},
169         {"final",               nixio_crypto_hash_final},
170         {"__gc",                nixio_crypto_hash__gc},
171         {"__tostring",  nixio_crypto_hash__tostring},
172         {NULL,                  NULL}
173 };
174
175
176
177 void nixio_open_tls_crypto(lua_State *L) {
178         luaL_newmetatable(L, NIXIO_CRYPTO_HASH_META);
179         luaL_register(L, NULL, M);
180         lua_pushvalue(L, -1);
181         lua_setfield(L, -2, "__index");
182         lua_pop(L, 1);
183
184         lua_newtable(L);
185     luaL_register(L, NULL, R);
186
187         lua_setfield(L, -2, "crypto");
188 }