lib-nixio / luci-base: Fix for reading csrf token prevents file upload
[project/luci.git] / libs / luci-lib-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 <stdlib.h>
21 #include <string.h>
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <unistd.h>
25
26 static int nixio_crypto_hash__init(lua_State *L, int hmac) {
27         const char *type = luaL_checkstring(L, 1);
28         nixio_hash *hash = lua_newuserdata(L, sizeof(nixio_hash));
29
30         if (!strcmp(type, "md5")) {
31                 hash->type = NIXIO_HASH_MD5;
32                 hash->digest_size = MD5_DIGEST_LENGTH;
33                 hash->block_size = 64;
34                 hash->ctx = malloc(sizeof(MD5_CTX));
35                 if (!hash->ctx) {
36                         return luaL_error(L, NIXIO_OOM);
37                 }
38                 MD5_Init((MD5_CTX*)hash->ctx);
39                 hash->init = (nixio_hash_initcb)MD5_Init;
40                 hash->update = (nixio_hash_updatecb)MD5_Update;
41                 hash->final = (nixio_hash_finalcb)MD5_Final;
42         } else if (!strcmp(type, "sha1")) {
43                 hash->type = NIXIO_HASH_SHA1;
44                 hash->digest_size = SHA_DIGEST_LENGTH;
45                 hash->block_size = 64;
46                 hash->ctx = malloc(sizeof(SHA_CTX));
47                 if (!hash->ctx) {
48                         return luaL_error(L, NIXIO_OOM);
49                 }
50                 SHA1_Init((SHA_CTX*)hash->ctx);
51                 hash->init = (nixio_hash_initcb)SHA1_Init;
52                 hash->update = (nixio_hash_updatecb)SHA1_Update;
53                 hash->final = (nixio_hash_finalcb)SHA1_Final;
54         } else {
55                 luaL_argerror(L, 1, "supported values: md5, sha1");
56         }
57
58         luaL_getmetatable(L, NIXIO_CRYPTO_HASH_META);
59         lua_setmetatable(L, -2);
60
61         if (hmac) {
62                 const char *key = luaL_checklstring(L, 2, &hash->key_size);
63                 if (hash->key_size > hash->block_size) {
64                         hash->update(hash->ctx, key, hash->key_size);
65                         hash->final(hash->digest, hash->ctx);
66                         hash->init(hash->ctx);
67                         hash->key_size = hash->digest_size;
68                         memcpy(hash->key, hash->digest, hash->key_size);
69                 } else {
70                         memcpy(hash->key, key, hash->key_size);
71                 }
72
73                 unsigned char pad[NIXIO_CRYPTO_BLOCK_SIZE];
74                 for (uint i = 0; i < hash->block_size; i++) {
75                         pad[i] = (i < hash->key_size) ? (0x36 ^ hash->key[i]) : 0x36;
76                 }
77                 hash->update(hash->ctx, pad, hash->block_size);
78                 hash->type |= NIXIO_HMAC_BIT;
79         }
80
81         return 1;
82 }
83
84 static int nixio_crypto_hash(lua_State *L) {
85         return nixio_crypto_hash__init(L, 0);
86 }
87
88 static int nixio_crypto_hmac(lua_State *L) {
89         return nixio_crypto_hash__init(L, 1);
90 }
91
92 static int nixio_crypto_hash_update(lua_State *L) {
93         nixio_hash *hash = luaL_checkudata(L, 1, NIXIO_CRYPTO_HASH_META);
94         if (hash->type) {
95                 size_t len;
96                 const char *chunk = luaL_checklstring(L, 2, &len);
97                 hash->update(hash->ctx, chunk, len);
98                 lua_pushvalue(L, 1);
99                 return 1;
100         } else {
101                 return luaL_error(L, "Tried to update finalized hash object.");
102         }
103 }
104
105 static int nixio_crypto_hash_final(lua_State *L) {
106         nixio_hash *hash = luaL_checkudata(L, 1, NIXIO_CRYPTO_HASH_META);
107         if (hash->type & NIXIO_HMAC_BIT) {
108                 hash->final(hash->digest, hash->ctx);
109                 hash->init(hash->ctx);
110
111                 unsigned char pad[NIXIO_CRYPTO_BLOCK_SIZE];
112                 for (uint i = 0; i < hash->block_size; i++) {
113                         pad[i] = (i < hash->key_size) ? (0x5c ^ hash->key[i]) : 0x5c;
114                 }
115
116                 hash->update(hash->ctx, pad, hash->block_size);
117                 hash->update(hash->ctx, hash->digest, hash->digest_size);
118         }
119
120         if (hash->type) {
121                 hash->type = NIXIO_HASH_NONE;
122                 hash->final(hash->digest, hash->ctx);
123                 free(hash->ctx);
124         }
125
126         char hashdigest[NIXIO_DIGEST_SIZE*2];
127         for (uint i=0; i < hash->digest_size; i++) {
128                 hashdigest[2*i]   = nixio__bin2hex[(hash->digest[i] & 0xf0) >> 4];
129                 hashdigest[2*i+1] = nixio__bin2hex[(hash->digest[i] & 0x0f)];
130         }
131
132         lua_pushlstring(L, hashdigest, hash->digest_size * 2);
133         memcpy(hashdigest, hash->digest, hash->digest_size);
134         lua_pushlstring(L, hashdigest, hash->digest_size);
135
136         return 2;
137 }
138
139 static int nixio_crypto_hash__gc(lua_State *L) {
140         nixio_hash *hash = luaL_checkudata(L, 1, NIXIO_CRYPTO_HASH_META);
141         if (hash->type) {
142                 hash->final(hash->digest, hash->ctx);
143                 free(hash->ctx);
144                 hash->type = NIXIO_HASH_NONE;
145         }
146         return 0;
147 }
148
149 static int nixio_crypto_hash__tostring(lua_State *L) {
150         nixio_hash *hash = luaL_checkudata(L, 1, NIXIO_CRYPTO_HASH_META);
151         lua_pushfstring(L, "nixio hash object: %p", hash);
152         return 1;
153 }
154
155
156 /* module table */
157 static const luaL_reg R[] = {
158         {"hash",                nixio_crypto_hash},
159         {"hmac",                nixio_crypto_hmac},
160         {NULL,                  NULL}
161 };
162
163 /* hash table */
164 static const luaL_reg M[] = {
165         {"update",              nixio_crypto_hash_update},
166         {"final",               nixio_crypto_hash_final},
167         {"__gc",                nixio_crypto_hash__gc},
168         {"__tostring",  nixio_crypto_hash__tostring},
169         {NULL,                  NULL}
170 };
171
172
173
174 void nixio_open_tls_crypto(lua_State *L) {
175         luaL_newmetatable(L, NIXIO_CRYPTO_HASH_META);
176         luaL_register(L, NULL, M);
177         lua_pushvalue(L, -1);
178         lua_setfield(L, -2, "__index");
179         lua_pop(L, 1);
180
181         lua_newtable(L);
182     luaL_register(L, NULL, R);
183
184         lua_setfield(L, -2, "crypto");
185 }