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