Delta Chat Core C-Library
mrkey.c
1 /*******************************************************************************
2  *
3  * Delta Chat Core
4  * Copyright (C) 2017 Björn Petersen
5  * Contact: r10s@b44t.com, http://b44t.com
6  *
7  * This program is free software: you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License as published by the Free Software
9  * Foundation, either version 3 of the License, or (at your option) any later
10  * version.
11  *
12  * This program is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
15  * details.
16  *
17  * You should have received a copy of the GNU General Public License along with
18  * this program. If not, see http://www.gnu.org/licenses/ .
19  *
20  ******************************************************************************/
21 
22 
23 #include "mrmailbox_internal.h"
24 #include <memory.h>
25 #include "mrkey.h"
26 #include "mrpgp.h"
27 #include "mrtools.h"
28 
29 
30 /*******************************************************************************
31  * Main interface
32  ******************************************************************************/
33 
34 
35 void mr_wipe_secret_mem(void* buf, size_t buf_bytes)
36 {
37  /* wipe private keys or othere secrets with zeros so that secrets are no longer in RAM */
38  if( buf == NULL || buf_bytes <= 0 ) {
39  return;
40  }
41 
42  memset(buf, 0x00, buf_bytes);
43 }
44 
45 
46 static void mrkey_empty(mrkey_t* ths) /* only use before calling setters; take care when using this function together with reference counting, prefer new objects instead */
47 {
48  if( ths == NULL ) {
49  return;
50  }
51 
52  if( ths->m_type==MR_PRIVATE ) {
53  mr_wipe_secret_mem(ths->m_binary, ths->m_bytes);
54  }
55 
56  free(ths->m_binary);
57  ths->m_binary = NULL;
58  ths->m_bytes = 0;
59  ths->m_type = MR_PUBLIC;
60 }
61 
62 
63 mrkey_t* mrkey_new()
64 {
65  mrkey_t* ths;
66 
67  if( (ths=calloc(1, sizeof(mrkey_t)))==NULL ) {
68  exit(44); /* cannot allocate little memory, unrecoverable error */
69  }
70  ths->_m_heap_refcnt = 1;
71  return ths;
72 }
73 
74 
75 mrkey_t* mrkey_ref(mrkey_t* ths)
76 {
77  if( ths==NULL ) {
78  return NULL;
79  }
80  ths->_m_heap_refcnt++;
81  return ths;
82 }
83 
84 
85 void mrkey_unref(mrkey_t* ths)
86 {
87  if( ths==NULL ) {
88  return;
89  }
90 
91  ths->_m_heap_refcnt--;
92  if( ths->_m_heap_refcnt != 0 ) {
93  return;
94  }
95 
96  mrkey_empty(ths);
97  free(ths);
98 }
99 
100 
101 int mrkey_set_from_raw(mrkey_t* ths, const void* data, int bytes, int type)
102 {
103  mrkey_empty(ths);
104  if( ths==NULL || data==NULL || bytes <= 0 ) {
105  return 0;
106  }
107  ths->m_binary = malloc(bytes);
108  if( ths->m_binary == NULL ) {
109  exit(40);
110  }
111  memcpy(ths->m_binary, data, bytes);
112  ths->m_bytes = bytes;
113  ths->m_type = type;
114  return 1;
115 }
116 
117 
118 int mrkey_set_from_key(mrkey_t* ths, const mrkey_t* o)
119 {
120  mrkey_empty(ths);
121  if( ths==NULL || o==NULL ) {
122  return 0;
123  }
124  return mrkey_set_from_raw(ths, o->m_binary, o->m_bytes, o->m_type);
125 }
126 
127 
128 int mrkey_set_from_stmt(mrkey_t* ths, sqlite3_stmt* stmt, int index, int type)
129 {
130  mrkey_empty(ths);
131  if( ths==NULL || stmt==NULL ) {
132  return 0;
133  }
134  return mrkey_set_from_raw(ths, (unsigned char*)sqlite3_column_blob(stmt, index), sqlite3_column_bytes(stmt, index), type);
135 }
136 
137 
138 int mrkey_set_from_base64(mrkey_t* ths, const char* base64, int type)
139 {
140  size_t indx = 0, result_len = 0;
141  char* result = NULL;
142 
143  mrkey_empty(ths);
144 
145  if( ths==NULL || base64==NULL ) {
146  return 0;
147  }
148 
149  if( mailmime_base64_body_parse(base64, strlen(base64), &indx, &result/*must be freed using mmap_string_unref()*/, &result_len)!=MAILIMF_NO_ERROR
150  || result == NULL || result_len == 0 ) {
151  return 0; /* bad key */
152  }
153 
154  mrkey_set_from_raw(ths, result, result_len, type);
155  mmap_string_unref(result);
156 
157  return 1;
158 }
159 
160 
161 int mrkey_set_from_file(mrkey_t* ths, const char* pathNfilename, mrmailbox_t* mailbox)
162 {
163  char* buf = NULL;
164  char *p1, *p2; /* just pointers inside buf, must not be freed */
165  size_t buf_bytes;
166  int type = -1, success = 0;
167 
168  mrkey_empty(ths);
169 
170  if( ths==NULL || pathNfilename==NULL ) {
171  goto cleanup;
172  }
173 
174  if( !mr_read_file(pathNfilename, (void**)&buf, &buf_bytes, mailbox)
175  || buf_bytes < 50 ) {
176  goto cleanup; /* error is already loged */
177  }
178 
179  mr_remove_cr_chars(buf); /* make comparison easier */
180  mr_trim(buf);
181 
182  if( strncmp(buf, "-----BEGIN PGP PUBLIC KEY BLOCK-----\n", 37)==0 ) {
183  if( mr_str_replace(&buf, "-----END PGP PUBLIC KEY BLOCK-----", "")!=1 ) {
184  mrmailbox_log_warning(mailbox, 0, "Bad header for key \"%s\".", pathNfilename);
185  goto cleanup;
186  }
187  type = MR_PUBLIC;
188  p1 = buf + 37; /* must be done after buf-pointer modification in mr_str_replace() */
189  }
190  else if( strncmp(buf, "-----BEGIN PGP PRIVATE KEY BLOCK-----\n", 38)==0 ) {
191  if( mr_str_replace(&buf, "-----END PGP PRIVATE KEY BLOCK-----", "")!=1 ) {
192  mrmailbox_log_warning(mailbox, 0, "Bad header for key \"%s\".", pathNfilename);
193  goto cleanup;
194  }
195  type = MR_PRIVATE;
196  p1 = buf + 38; /* must be done after buf-pointer modification in mr_str_replace() */
197  }
198  else {
199  mrmailbox_log_warning(mailbox, 0, "Header missing for key \"%s\".", pathNfilename);
200  goto cleanup;
201  }
202 
203  /* base64 starts after first empty line, if any */
204  p2 = strstr(p1, "\n\n"); /* `\r* is already removed above */
205  if( p2 ) {
206  p1 = p2;
207  }
208 
209  if( !mrkey_set_from_base64(ths, p1, type) ) {
210  mrmailbox_log_warning(mailbox, 0, "Bad data in key \"%s\".", pathNfilename);
211  goto cleanup;
212  }
213 
214  success = 1;
215 
216 cleanup:
217  free(buf);
218  return success;
219 }
220 
221 
222 int mrkey_equals(const mrkey_t* ths, const mrkey_t* o)
223 {
224  if( ths==NULL || o==NULL
225  || ths->m_binary==NULL || ths->m_bytes<=0 || o->m_binary==NULL || o->m_bytes<=0 ) {
226  return 0; /*error*/
227  }
228 
229  if( ths->m_bytes != o->m_bytes ) {
230  return 0; /*different size -> the keys cannot be equal*/
231  }
232 
233  if( ths->m_type != o->m_type ) {
234  return 0; /* cannot compare public with private keys */
235  }
236 
237  return memcmp(ths->m_binary, o->m_binary, o->m_bytes)==0? 1 : 0;
238 }
239 
240 
241 /*******************************************************************************
242  * Save/Load keys
243  ******************************************************************************/
244 
245 
246 int mrkey_save_self_keypair__(const mrkey_t* public_key, const mrkey_t* private_key, const char* addr, int is_default, mrsqlite3_t* sql)
247 {
248  sqlite3_stmt* stmt;
249 
250  if( public_key==NULL || private_key==NULL || addr==NULL || sql==NULL
251  || public_key->m_binary==NULL || private_key->m_binary==NULL ) {
252  return 0;
253  }
254 
255  stmt = mrsqlite3_predefine__(sql, INSERT_INTO_keypairs_aippc,
256  "INSERT INTO keypairs (addr, is_default, public_key, private_key, created) VALUES (?,?,?,?,?);");
257  sqlite3_bind_text (stmt, 1, addr, -1, SQLITE_STATIC);
258  sqlite3_bind_int (stmt, 2, is_default);
259  sqlite3_bind_blob (stmt, 3, public_key->m_binary, public_key->m_bytes, SQLITE_STATIC);
260  sqlite3_bind_blob (stmt, 4, private_key->m_binary, private_key->m_bytes, SQLITE_STATIC);
261  sqlite3_bind_int64(stmt, 5, time(NULL));
262  if( sqlite3_step(stmt) != SQLITE_DONE ) {
263  return 0;
264  }
265 
266  return 1;
267 }
268 
269 
270 int mrkey_load_self_public__(mrkey_t* ths, const char* self_addr, mrsqlite3_t* sql)
271 {
272  sqlite3_stmt* stmt;
273 
274  if( ths==NULL || self_addr==NULL || sql==NULL ) {
275  return 0;
276  }
277 
278  mrkey_empty(ths);
279  stmt = mrsqlite3_predefine__(sql, SELECT_public_key_FROM_keypairs_WHERE_default,
280  "SELECT public_key FROM keypairs WHERE addr=? AND is_default=1;");
281  sqlite3_bind_text (stmt, 1, self_addr, -1, SQLITE_STATIC);
282  if( sqlite3_step(stmt) != SQLITE_ROW ) {
283  return 0;
284  }
285  mrkey_set_from_stmt(ths, stmt, 0, MR_PUBLIC);
286  return 1;
287 }
288 
289 
290 int mrkey_load_self_private__(mrkey_t* ths, const char* self_addr, mrsqlite3_t* sql)
291 {
292  sqlite3_stmt* stmt;
293 
294  if( ths==NULL || self_addr==NULL || sql==NULL ) {
295  return 0;
296  }
297 
298  mrkey_empty(ths);
299  stmt = mrsqlite3_predefine__(sql, SELECT_private_key_FROM_keypairs_WHERE_default,
300  "SELECT private_key FROM keypairs WHERE addr=? AND is_default=1;");
301  sqlite3_bind_text (stmt, 1, self_addr, -1, SQLITE_STATIC);
302  if( sqlite3_step(stmt) != SQLITE_ROW ) {
303  return 0;
304  }
305  mrkey_set_from_stmt(ths, stmt, 0, MR_PRIVATE);
306  return 1;
307 }
308 
309 
310 /*******************************************************************************
311  * Render keys
312  ******************************************************************************/
313 
314 
315 static long crc_octets(const unsigned char *octets, size_t len)
316 {
317  #define CRC24_INIT 0xB704CEL
318  #define CRC24_POLY 0x1864CFBL
319  long crc = CRC24_INIT;
320  int i;
321  while (len--) {
322  crc ^= (*octets++) << 16;
323  for (i = 0; i < 8; i++) {
324  crc <<= 1;
325  if (crc & 0x1000000)
326  crc ^= CRC24_POLY;
327  }
328  }
329  return crc & 0xFFFFFFL;
330 }
331 
332 
333 char* mr_render_base64(const void* buf, size_t buf_bytes, int break_every, const char* break_chars,
334  int add_checksum /*0=no checksum, 1=add without break, 2=add with break_chars*/)
335 {
336  char* ret = NULL;
337 
338  if( buf==NULL || buf_bytes<=0 ) {
339  goto cleanup;
340  }
341 
342  if( (ret = encode_base64((const char*)buf, buf_bytes))==NULL ) {
343  goto cleanup;
344  }
345 
346  #if 0
347  if( add_checksum == 1/*appended checksum*/ ) {
348  long checksum = crc_octets(buf, buf_bytes);
349  uint8_t c[3];
350  c[0] = (uint8_t)((checksum >> 16)&0xFF);
351  c[1] = (uint8_t)((checksum >> 8)&0xFF);
352  c[2] = (uint8_t)((checksum)&0xFF);
353  char* c64 = encode_base64((const char*)c, 3);
354  char* temp = ret;
355  ret = mr_mprintf("%s=%s", temp, c64);
356  free(temp);
357  free(c64);
358  }
359  #endif
360 
361  if( break_every>0 ) {
362  char* temp = ret;
363  ret = mr_insert_breaks(temp, break_every, break_chars);
364  free(temp);
365  }
366 
367  if( add_checksum == 2/*checksum with break character*/ ) {
368  long checksum = crc_octets(buf, buf_bytes);
369  uint8_t c[3];
370  c[0] = (uint8_t)((checksum >> 16)&0xFF);
371  c[1] = (uint8_t)((checksum >> 8)&0xFF);
372  c[2] = (uint8_t)((checksum)&0xFF);
373  char* c64 = encode_base64((const char*)c, 3);
374  char* temp = ret;
375  ret = mr_mprintf("%s%s=%s", temp, break_chars, c64);
376  free(temp);
377  free(c64);
378  }
379 
380 cleanup:
381  return ret;
382 }
383 
384 
385 char* mrkey_render_base64(const mrkey_t* ths, int break_every, const char* break_chars, int add_checksum)
386 {
387  if( ths==NULL ) {
388  return NULL;
389  }
390  return mr_render_base64(ths->m_binary, ths->m_bytes, break_every, break_chars, add_checksum);
391 }
392 
393 
394 char* mrkey_render_asc(const mrkey_t* ths, const char* add_header_lines /*must be terminated by \r\n*/)
395 {
396  /* see RFC 4880, 6.2. Forming ASCII Armor, https://tools.ietf.org/html/rfc4880#section-6.2 */
397  char *base64 = NULL, *ret = NULL;
398 
399  if( ths==NULL ) {
400  goto cleanup;
401  }
402 
403  if( (base64=mrkey_render_base64(ths, 76, "\r\n", 2/*checksum in new line*/))==NULL ) { /* RFC: The encoded output stream must be represented in lines of no more than 76 characters each. */
404  goto cleanup;
405  }
406 
407  ret = mr_mprintf("-----BEGIN PGP %s KEY BLOCK-----\r\n%s\r\n%s\r\n-----END PGP %s KEY BLOCK-----\r\n",
408  ths->m_type==MR_PUBLIC? "PUBLIC" : "PRIVATE",
409  add_header_lines? add_header_lines : "",
410  base64,
411  ths->m_type==MR_PUBLIC? "PUBLIC" : "PRIVATE");
412 
413 cleanup:
414  free(base64);
415  return ret;
416 }
417 
418 
419 char* mr_render_fingerprint(const uint8_t* data, size_t bytes)
420 {
421  int i;
422  char* temp;
423 
424  if( data ==NULL || bytes <= 0 ) {
425  return safe_strdup("ErrFingerprint2");
426  }
427 
428  char* ret = malloc(bytes*4+1); if( ret==NULL ) { exit(46); }
429  ret[0] = 0;
430 
431  for( i = 0; i < bytes; i++ ) {
432  temp = mr_mprintf("%02X%s", (int)data[i], (i==6||i==13)?"\n":" ");
433  strcat(ret, temp);
434  free(temp);
435  }
436 
437  return ret;
438 }
439 
440 
441 char* mrkey_render_fingerprint(const mrkey_t* key, mrmailbox_t* mailbox)
442 {
443  uint8_t* fingerprint_buf = NULL;
444  size_t fingerprint_bytes = 0;
445 
446  if( key==NULL || mailbox == NULL ) {
447  return safe_strdup("ErrFingerprint0");
448  }
449 
450  if( !mrpgp_calc_fingerprint(mailbox, key, &fingerprint_buf, &fingerprint_bytes) ) {
451  return safe_strdup("ErrFingerprint1");
452  }
453 
454  char* fingerprint_str = mr_render_fingerprint(fingerprint_buf, fingerprint_bytes);
455  free(fingerprint_buf);
456  return fingerprint_str;
457 }
458 
An object representing a single mailbox.
Definition: mrmailbox.h:141