2008-08-06 18:36:30 +00:00
|
|
|
// This file is part of BOINC.
|
2005-01-20 23:22:22 +00:00
|
|
|
// http://boinc.berkeley.edu
|
2008-08-06 18:36:30 +00:00
|
|
|
// Copyright (C) 2008 University of California
|
2003-09-03 05:42:33 +00:00
|
|
|
//
|
2008-08-06 18:36:30 +00:00
|
|
|
// BOINC is free software; you can redistribute it and/or modify it
|
|
|
|
// under the terms of the GNU Lesser General Public License
|
|
|
|
// as published by the Free Software Foundation,
|
|
|
|
// either version 3 of the License, or (at your option) any later version.
|
2003-09-03 05:42:33 +00:00
|
|
|
//
|
2008-08-06 18:36:30 +00:00
|
|
|
// BOINC is distributed in the hope that it will be useful,
|
2005-01-20 23:22:22 +00:00
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
// See the GNU Lesser General Public License for more details.
|
2002-09-26 18:11:06 +00:00
|
|
|
//
|
2008-08-06 18:36:30 +00:00
|
|
|
// You should have received a copy of the GNU Lesser General Public License
|
|
|
|
// along with BOINC. If not, see <http://www.gnu.org/licenses/>.
|
2002-09-26 18:11:06 +00:00
|
|
|
|
2010-05-11 19:10:29 +00:00
|
|
|
#if defined(_WIN32) && !defined(__STDWX_H__)
|
2004-06-16 23:16:08 +00:00
|
|
|
#include "boinc_win.h"
|
2010-05-11 19:10:29 +00:00
|
|
|
#elif defined(_WIN32) && defined(__STDWX_H__)
|
|
|
|
#include "stdwx.h"
|
|
|
|
#else
|
2005-11-21 18:34:44 +00:00
|
|
|
#include "config.h"
|
2003-10-10 05:28:38 +00:00
|
|
|
#include <cctype>
|
2004-07-13 13:54:09 +00:00
|
|
|
#include <cstdio>
|
|
|
|
#include <cstdlib>
|
2007-12-21 21:09:40 +00:00
|
|
|
#include <cstring>
|
2008-09-04 12:50:54 +00:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <fcntl.h>
|
2004-03-04 11:41:43 +00:00
|
|
|
#endif
|
2002-06-14 05:49:34 +00:00
|
|
|
|
2010-05-11 19:10:29 +00:00
|
|
|
#ifdef _MSC_VER
|
|
|
|
#define snprintf _snprintf
|
|
|
|
#define strdup _strdup
|
|
|
|
#endif
|
|
|
|
|
2008-09-04 12:50:54 +00:00
|
|
|
#include <openssl/ssl.h>
|
|
|
|
#include <openssl/md5.h>
|
|
|
|
#include <openssl/bio.h>
|
|
|
|
#include <openssl/evp.h>
|
|
|
|
#include <openssl/pem.h>
|
|
|
|
#include <openssl/conf.h>
|
|
|
|
#include <openssl/engine.h>
|
|
|
|
#include <openssl/err.h>
|
|
|
|
|
2002-06-14 05:49:34 +00:00
|
|
|
#include "md5_file.h"
|
2008-09-04 12:50:54 +00:00
|
|
|
#include "cert_sig.h"
|
2008-09-04 13:18:51 +00:00
|
|
|
#include "filesys.h"
|
2002-07-11 01:09:53 +00:00
|
|
|
#include "error_numbers.h"
|
2002-06-14 05:49:34 +00:00
|
|
|
|
2002-08-30 20:56:02 +00:00
|
|
|
#include "crypt.h"
|
|
|
|
|
2004-07-03 21:38:15 +00:00
|
|
|
#ifdef _USING_FCGI_
|
2008-09-09 19:10:42 +00:00
|
|
|
#include "boinc_fcgi.h"
|
2004-07-03 21:38:15 +00:00
|
|
|
#endif
|
|
|
|
|
2002-07-09 00:10:58 +00:00
|
|
|
// NOTE: the fast CGI I/O library doesn't have fscanf(),
|
|
|
|
// so some of the following have been modified to use
|
|
|
|
// fgets() and sscanf() instead
|
|
|
|
|
2002-07-05 05:33:40 +00:00
|
|
|
// write some data in hex notation.
|
2002-06-14 05:49:34 +00:00
|
|
|
// NOTE: since length may not be known to the reader,
|
|
|
|
// we follow the data with a non-hex character '.'
|
|
|
|
//
|
|
|
|
int print_hex_data(FILE* f, DATA_BLOCK& x) {
|
2002-07-11 01:09:53 +00:00
|
|
|
unsigned int i;
|
2002-08-30 20:56:02 +00:00
|
|
|
|
2002-06-14 05:49:34 +00:00
|
|
|
for (i=0; i<x.len; i++) {
|
|
|
|
fprintf(f, "%02x", x.data[i]);
|
|
|
|
if (i%32==31) fprintf(f, "\n");
|
|
|
|
}
|
|
|
|
if (x.len%32 != 0) fprintf(f, "\n");
|
|
|
|
fprintf(f, ".\n");
|
2002-07-11 01:09:53 +00:00
|
|
|
return 0;
|
2002-06-14 05:49:34 +00:00
|
|
|
}
|
|
|
|
|
2002-07-05 05:33:40 +00:00
|
|
|
// same, but write to buffer
|
|
|
|
//
|
2008-05-09 21:27:22 +00:00
|
|
|
int sprint_hex_data(char* out_buf, DATA_BLOCK& x) {
|
2002-07-11 01:09:53 +00:00
|
|
|
unsigned int i;
|
2008-05-09 21:27:22 +00:00
|
|
|
const char hex[] = "0123456789abcdef";
|
|
|
|
char* p = out_buf;
|
2002-08-30 20:56:02 +00:00
|
|
|
|
2002-07-05 05:33:40 +00:00
|
|
|
for (i=0; i<x.len; i++) {
|
2008-05-09 21:27:22 +00:00
|
|
|
*p++ = hex[x.data[i]/16];
|
|
|
|
*p++ = hex[x.data[i]%16];
|
|
|
|
if (i%32==31) *p++ = '\n';
|
2002-07-05 05:33:40 +00:00
|
|
|
}
|
2008-05-09 21:27:22 +00:00
|
|
|
if (x.len%32 != 0) *p++ = '\n';
|
|
|
|
strcpy(p, ".\n");
|
2002-07-16 19:31:37 +00:00
|
|
|
|
2002-07-11 01:09:53 +00:00
|
|
|
return 0;
|
2002-07-05 05:33:40 +00:00
|
|
|
}
|
|
|
|
|
2008-09-04 15:13:54 +00:00
|
|
|
int print_raw_data(FILE* f, DATA_BLOCK& x) {
|
|
|
|
unsigned int i;
|
|
|
|
for (i=0; i<x.len; i++) {
|
|
|
|
//printf("%x ", x.data[i]);
|
|
|
|
fprintf(f, "%c", x.data[i]);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// NOTE: buffer must be big enough; no checking is done.
|
|
|
|
int scan_raw_data(FILE *f, DATA_BLOCK& x) {
|
|
|
|
int i=0,j;
|
|
|
|
while(EOF!=(j=fgetc(f))) {
|
|
|
|
x.data[i]=j;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
x.len = i;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2002-06-14 05:49:34 +00:00
|
|
|
// scan data in hex notation.
|
|
|
|
// stop when you reach a non-parsed character.
|
2002-07-09 00:10:58 +00:00
|
|
|
// NOTE: buffer must be big enough; no checking is done.
|
2002-06-14 05:49:34 +00:00
|
|
|
//
|
|
|
|
int scan_hex_data(FILE* f, DATA_BLOCK& x) {
|
|
|
|
int n;
|
2002-08-30 20:56:02 +00:00
|
|
|
|
2002-06-14 05:49:34 +00:00
|
|
|
x.len = 0;
|
2002-07-09 00:10:58 +00:00
|
|
|
#if _USING_FCGI_
|
|
|
|
char *p, buf[256];
|
2002-07-11 01:09:53 +00:00
|
|
|
int i, j;
|
2002-07-09 00:10:58 +00:00
|
|
|
while (1) {
|
|
|
|
p = fgets(buf, 256, f);
|
2003-10-21 04:06:55 +00:00
|
|
|
if (!p) return ERR_GETS;
|
2002-07-09 00:10:58 +00:00
|
|
|
n = strlen(p)/2;
|
|
|
|
if (n == 0) break;
|
|
|
|
for (i=0; i<n; i++) {
|
|
|
|
sscanf(buf+i*2, "%2x", &j);
|
|
|
|
x.data[x.len] = j;
|
|
|
|
x.len++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
2002-06-14 05:49:34 +00:00
|
|
|
while (1) {
|
2003-06-17 20:18:56 +00:00
|
|
|
int j;
|
|
|
|
n = fscanf(f, "%2x", &j);
|
2002-07-09 00:10:58 +00:00
|
|
|
if (n <= 0) break;
|
2003-06-17 20:18:56 +00:00
|
|
|
x.data[x.len] = j;
|
2002-06-14 05:49:34 +00:00
|
|
|
x.len++;
|
|
|
|
}
|
2002-07-09 00:10:58 +00:00
|
|
|
#endif
|
2002-06-14 05:49:34 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2002-07-05 05:33:40 +00:00
|
|
|
// same, but read from buffer
|
|
|
|
//
|
2005-02-16 23:17:43 +00:00
|
|
|
static int sscan_hex_data(const char* p, DATA_BLOCK& x) {
|
2002-07-07 20:39:24 +00:00
|
|
|
int m, n, nleft=x.len;
|
2002-08-30 20:56:02 +00:00
|
|
|
|
2002-07-05 05:33:40 +00:00
|
|
|
x.len = 0;
|
|
|
|
while (1) {
|
2003-10-10 05:28:38 +00:00
|
|
|
if (isspace(*p)) {
|
|
|
|
++p;
|
|
|
|
continue;
|
|
|
|
}
|
2002-07-07 20:39:24 +00:00
|
|
|
n = sscanf(p, "%2x", &m);
|
2002-07-05 05:33:40 +00:00
|
|
|
if (n <= 0) break;
|
2002-07-07 20:39:24 +00:00
|
|
|
x.data[x.len++] = m;
|
|
|
|
nleft--;
|
|
|
|
if (nleft<0) {
|
|
|
|
fprintf(stderr, "sscan_hex_data: buffer overflow\n");
|
2003-09-03 23:54:11 +00:00
|
|
|
return ERR_BAD_HEX_FORMAT;
|
2002-07-07 20:39:24 +00:00
|
|
|
}
|
2002-07-05 05:33:40 +00:00
|
|
|
p += 2;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2002-06-14 05:49:34 +00:00
|
|
|
// print a key in ASCII form
|
|
|
|
//
|
|
|
|
int print_key_hex(FILE* f, KEY* key, int size) {
|
2002-07-11 01:09:53 +00:00
|
|
|
int len;
|
2002-06-14 05:49:34 +00:00
|
|
|
DATA_BLOCK x;
|
2002-08-30 20:56:02 +00:00
|
|
|
|
2002-06-14 05:49:34 +00:00
|
|
|
fprintf(f, "%d\n", key->bits);
|
|
|
|
len = size - sizeof(key->bits);
|
|
|
|
x.data = key->data;
|
|
|
|
x.len = len;
|
|
|
|
return print_hex_data(f, x);
|
|
|
|
}
|
|
|
|
|
|
|
|
int scan_key_hex(FILE* f, KEY* key, int size) {
|
2002-07-05 05:33:40 +00:00
|
|
|
int len, i, n;
|
2002-07-09 00:10:58 +00:00
|
|
|
int num_bits;
|
2002-08-30 20:56:02 +00:00
|
|
|
|
2002-07-09 00:10:58 +00:00
|
|
|
#if _USING_FCGI_
|
2002-07-11 01:09:53 +00:00
|
|
|
char *p, buf[256];
|
2002-07-09 00:10:58 +00:00
|
|
|
int j = 0, b;
|
|
|
|
fgets(buf, 256, f);
|
2002-07-05 22:02:01 +00:00
|
|
|
sscanf(buf, "%d", &num_bits);
|
|
|
|
key->bits = num_bits;
|
2002-06-14 05:49:34 +00:00
|
|
|
len = size - sizeof(key->bits);
|
2002-07-09 00:10:58 +00:00
|
|
|
while (1) {
|
|
|
|
p = fgets(buf, 256, f);
|
2008-02-06 19:32:51 +00:00
|
|
|
if (!p) break;
|
|
|
|
n = (strlen(p)-1)/2;
|
2002-07-09 00:10:58 +00:00
|
|
|
if (n == 0) break;
|
|
|
|
for (i=0; i<n; i++) {
|
|
|
|
sscanf(buf+i*2, "%2x", &b);
|
2008-02-06 19:32:51 +00:00
|
|
|
if (j == len) break;
|
2002-07-09 00:10:58 +00:00
|
|
|
key->data[j++] = b;
|
2002-07-05 22:02:01 +00:00
|
|
|
}
|
2002-06-14 05:49:34 +00:00
|
|
|
}
|
2008-02-06 19:32:51 +00:00
|
|
|
if (j != len) return ERR_NULL;
|
2002-07-09 00:10:58 +00:00
|
|
|
#else
|
|
|
|
fscanf(f, "%d", &num_bits);
|
|
|
|
key->bits = num_bits;
|
|
|
|
len = size - sizeof(key->bits);
|
|
|
|
for (i=0; i<len; i++) {
|
|
|
|
fscanf(f, "%2x", &n);
|
|
|
|
key->data[i] = n;
|
|
|
|
}
|
|
|
|
fscanf(f, ".");
|
|
|
|
#endif
|
2002-06-14 05:49:34 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2002-07-07 20:39:24 +00:00
|
|
|
// parse a text-encoded key from a memory buffer
|
|
|
|
//
|
2005-02-16 23:17:43 +00:00
|
|
|
int sscan_key_hex(const char* buf, KEY* key, int size) {
|
2002-07-11 01:09:53 +00:00
|
|
|
int n, retval,num_bits;
|
2002-07-07 20:39:24 +00:00
|
|
|
DATA_BLOCK db;
|
2002-07-16 19:31:37 +00:00
|
|
|
|
2002-07-11 01:09:53 +00:00
|
|
|
//fprintf(stderr, "buf = %s\n", buf);
|
|
|
|
n = sscanf(buf, "%d", &num_bits);
|
|
|
|
key->bits = num_bits; //key->bits is a short
|
|
|
|
//fprintf(stderr, "key->bits = %d\n", key->bits);
|
2002-07-16 19:31:37 +00:00
|
|
|
|
2006-12-19 20:49:12 +00:00
|
|
|
if (n != 1) return ERR_XML_PARSE;
|
2002-07-07 20:39:24 +00:00
|
|
|
buf = strchr(buf, '\n');
|
2006-12-19 20:49:12 +00:00
|
|
|
if (!buf) return ERR_XML_PARSE;
|
2002-07-07 20:39:24 +00:00
|
|
|
buf += 1;
|
|
|
|
db.data = key->data;
|
2002-07-11 01:09:53 +00:00
|
|
|
db.len = size - sizeof(key->bits); //huh???
|
2002-07-07 20:39:24 +00:00
|
|
|
retval = sscan_hex_data(buf, db);
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2002-06-14 05:49:34 +00:00
|
|
|
// encrypt some data.
|
|
|
|
// The amount encrypted may be less than what's supplied.
|
|
|
|
// The output buffer must be at least MIN_OUT_BUFFER_SIZE.
|
|
|
|
// The output block must be decrypted in its entirety.
|
|
|
|
//
|
2005-08-11 17:41:08 +00:00
|
|
|
int encrypt_private(R_RSA_PRIVATE_KEY& key, DATA_BLOCK& in, DATA_BLOCK& out) {
|
2009-01-12 16:36:14 +00:00
|
|
|
int n, modulus_len, retval;
|
2002-08-30 20:56:02 +00:00
|
|
|
|
2002-07-05 05:33:40 +00:00
|
|
|
modulus_len = (key.bits+7)/8;
|
2002-06-14 05:49:34 +00:00
|
|
|
n = in.len;
|
2002-07-05 05:33:40 +00:00
|
|
|
if (n >= modulus_len-11) {
|
|
|
|
n = modulus_len-11;
|
2002-06-14 05:49:34 +00:00
|
|
|
}
|
2005-08-01 22:44:40 +00:00
|
|
|
RSA* rp = RSA_new();
|
|
|
|
private_to_openssl(key, rp);
|
2009-01-12 16:36:14 +00:00
|
|
|
retval = RSA_private_encrypt(n, in.data, out.data, rp, RSA_PKCS1_PADDING);
|
|
|
|
if (retval < 0) {
|
|
|
|
RSA_free(rp);
|
|
|
|
return ERR_CRYPTO;
|
|
|
|
}
|
2005-08-01 22:44:40 +00:00
|
|
|
out.len = RSA_size(rp);
|
|
|
|
RSA_free(rp);
|
2002-06-14 05:49:34 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int decrypt_public(R_RSA_PUBLIC_KEY& key, DATA_BLOCK& in, DATA_BLOCK& out) {
|
2009-01-12 16:36:14 +00:00
|
|
|
int retval;
|
2005-08-01 22:44:40 +00:00
|
|
|
RSA* rp = RSA_new();
|
|
|
|
public_to_openssl(key, rp);
|
2009-01-12 16:36:14 +00:00
|
|
|
retval = RSA_public_decrypt(in.len, in.data, out.data, rp, RSA_PKCS1_PADDING);
|
|
|
|
if (retval < 0) {
|
|
|
|
RSA_free(rp);
|
|
|
|
return ERR_CRYPTO;
|
|
|
|
}
|
2005-08-01 22:44:40 +00:00
|
|
|
out.len = RSA_size(rp);
|
2009-01-12 16:36:14 +00:00
|
|
|
RSA_free(rp);
|
2005-08-01 22:44:40 +00:00
|
|
|
return 0;
|
2002-06-14 05:49:34 +00:00
|
|
|
}
|
|
|
|
|
2005-02-16 23:17:43 +00:00
|
|
|
int sign_file(const char* path, R_RSA_PRIVATE_KEY& key, DATA_BLOCK& signature) {
|
2002-07-05 05:33:40 +00:00
|
|
|
char md5_buf[MD5_LEN];
|
2002-06-14 05:49:34 +00:00
|
|
|
double file_length;
|
|
|
|
DATA_BLOCK in_block;
|
2005-08-11 17:41:08 +00:00
|
|
|
int retval;
|
2002-08-30 20:56:02 +00:00
|
|
|
|
2002-06-14 05:49:34 +00:00
|
|
|
retval = md5_file(path, md5_buf, file_length);
|
|
|
|
if (retval) return retval;
|
|
|
|
in_block.data = (unsigned char*)md5_buf;
|
2005-11-13 20:59:27 +00:00
|
|
|
in_block.len = (unsigned int)strlen(md5_buf);
|
2005-08-11 17:41:08 +00:00
|
|
|
retval = encrypt_private(key, in_block, signature);
|
2002-06-14 05:49:34 +00:00
|
|
|
if (retval) return retval;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2002-07-05 05:33:40 +00:00
|
|
|
int sign_block(DATA_BLOCK& data_block, R_RSA_PRIVATE_KEY& key, DATA_BLOCK& signature) {
|
|
|
|
char md5_buf[MD5_LEN];
|
2005-08-11 17:41:08 +00:00
|
|
|
int retval;
|
2002-07-05 05:33:40 +00:00
|
|
|
DATA_BLOCK in_block;
|
|
|
|
|
|
|
|
md5_block(data_block.data, data_block.len, md5_buf);
|
|
|
|
in_block.data = (unsigned char*)md5_buf;
|
2005-11-13 20:59:27 +00:00
|
|
|
in_block.len = (unsigned int)strlen(md5_buf);
|
2005-08-11 17:41:08 +00:00
|
|
|
retval = encrypt_private(key, in_block, signature);
|
2002-07-05 05:33:40 +00:00
|
|
|
if (retval) {
|
|
|
|
printf("sign_block: encrypt_private returned %d\n", retval);
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-12-14 23:43:50 +00:00
|
|
|
// compute an XML signature element for some text
|
|
|
|
//
|
|
|
|
int generate_signature(
|
|
|
|
char* text_to_sign, char* signature_hex, R_RSA_PRIVATE_KEY& key
|
|
|
|
) {
|
|
|
|
DATA_BLOCK block, signature_data;
|
|
|
|
unsigned char signature_buf[SIGNATURE_SIZE_BINARY];
|
|
|
|
int retval;
|
|
|
|
|
|
|
|
block.data = (unsigned char*)text_to_sign;
|
2008-08-13 17:26:26 +00:00
|
|
|
block.len = (unsigned int)strlen(text_to_sign);
|
2005-12-14 23:43:50 +00:00
|
|
|
signature_data.data = signature_buf;
|
|
|
|
signature_data.len = SIGNATURE_SIZE_BINARY;
|
|
|
|
retval = sign_block(block, key, signature_data);
|
|
|
|
if (retval) return retval;
|
|
|
|
sprint_hex_data(signature_hex, signature_data);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2002-06-14 05:49:34 +00:00
|
|
|
int verify_file(
|
2005-02-16 23:17:43 +00:00
|
|
|
const char* path, R_RSA_PUBLIC_KEY& key, DATA_BLOCK& signature, bool& answer
|
2002-06-14 05:49:34 +00:00
|
|
|
) {
|
2002-07-07 20:39:24 +00:00
|
|
|
char md5_buf[MD5_LEN], clear_buf[MD5_LEN];
|
2002-06-14 05:49:34 +00:00
|
|
|
double file_length;
|
|
|
|
int n, retval;
|
|
|
|
DATA_BLOCK clear_signature;
|
2002-08-30 20:56:02 +00:00
|
|
|
|
2002-06-14 05:49:34 +00:00
|
|
|
retval = md5_file(path, md5_buf, file_length);
|
2002-07-11 01:09:53 +00:00
|
|
|
if (retval) {
|
|
|
|
fprintf(stderr, "error: verify_file: md5_file error %d\n", retval);
|
|
|
|
return retval;
|
|
|
|
}
|
2005-11-13 20:59:27 +00:00
|
|
|
n = (int)strlen(md5_buf);
|
2002-06-14 05:49:34 +00:00
|
|
|
clear_signature.data = (unsigned char*)clear_buf;
|
2002-07-07 20:39:24 +00:00
|
|
|
clear_signature.len = MD5_LEN;
|
2002-06-14 05:49:34 +00:00
|
|
|
retval = decrypt_public(key, signature, clear_signature);
|
2002-07-11 01:09:53 +00:00
|
|
|
if (retval) {
|
|
|
|
fprintf(stderr, "error: verify_file: decrypt_public error %d\n", retval);
|
|
|
|
return retval;
|
|
|
|
}
|
2002-06-14 05:49:34 +00:00
|
|
|
answer = !strncmp(md5_buf, clear_buf, n);
|
|
|
|
return 0;
|
|
|
|
}
|
2002-07-05 05:33:40 +00:00
|
|
|
|
2002-07-07 20:39:24 +00:00
|
|
|
int verify_file2(
|
2005-02-16 23:17:43 +00:00
|
|
|
const char* path, const char* signature_text, const char* key_text, bool& answer
|
2002-07-07 20:39:24 +00:00
|
|
|
) {
|
|
|
|
R_RSA_PUBLIC_KEY key;
|
|
|
|
unsigned char signature_buf[SIGNATURE_SIZE_BINARY];
|
|
|
|
int retval;
|
|
|
|
DATA_BLOCK signature;
|
2002-08-30 20:56:02 +00:00
|
|
|
|
2002-07-07 20:39:24 +00:00
|
|
|
retval = sscan_key_hex(key_text, (KEY*)&key, sizeof(key));
|
2002-07-11 01:09:53 +00:00
|
|
|
if (retval) {
|
|
|
|
fprintf(stderr, "error: verify_file2: sscan_key_hex did not work\n");
|
|
|
|
return retval;
|
|
|
|
}
|
2002-07-07 20:39:24 +00:00
|
|
|
signature.data = signature_buf;
|
|
|
|
signature.len = sizeof(signature_buf);
|
2003-09-03 23:54:11 +00:00
|
|
|
retval = sscan_hex_data(signature_text, signature);
|
|
|
|
if (retval) return retval;
|
2002-07-07 20:39:24 +00:00
|
|
|
return verify_file(path, key, signature, answer);
|
|
|
|
}
|
|
|
|
|
2002-07-05 05:33:40 +00:00
|
|
|
// verify, where both text and signature are char strings
|
|
|
|
//
|
|
|
|
int verify_string(
|
2005-02-16 23:17:43 +00:00
|
|
|
const char* text, const char* signature_text, R_RSA_PUBLIC_KEY& key, bool& answer
|
2002-07-05 05:33:40 +00:00
|
|
|
) {
|
|
|
|
char md5_buf[MD5_LEN];
|
2002-07-07 20:39:24 +00:00
|
|
|
unsigned char signature_buf[SIGNATURE_SIZE_BINARY];
|
2002-07-05 05:33:40 +00:00
|
|
|
char clear_buf[MD5_LEN];
|
|
|
|
int retval, n;
|
|
|
|
DATA_BLOCK signature, clear_signature;
|
2002-08-30 20:56:02 +00:00
|
|
|
|
2005-11-13 20:59:27 +00:00
|
|
|
retval = md5_block((const unsigned char*)text, (int)strlen(text), md5_buf);
|
2002-07-05 05:33:40 +00:00
|
|
|
if (retval) return retval;
|
2005-11-13 20:59:27 +00:00
|
|
|
n = (int)strlen(md5_buf);
|
2002-07-05 05:33:40 +00:00
|
|
|
signature.data = signature_buf;
|
2002-07-07 20:39:24 +00:00
|
|
|
signature.len = sizeof(signature_buf);
|
2003-09-03 23:54:11 +00:00
|
|
|
retval = sscan_hex_data(signature_text, signature);
|
|
|
|
if (retval) return retval;
|
2002-07-05 05:33:40 +00:00
|
|
|
clear_signature.data = (unsigned char*)clear_buf;
|
|
|
|
clear_signature.len = 256;
|
|
|
|
retval = decrypt_public(key, signature, clear_signature);
|
|
|
|
if (retval) return retval;
|
|
|
|
answer = !strncmp(md5_buf, clear_buf, n);
|
|
|
|
return 0;
|
|
|
|
}
|
2002-07-07 20:39:24 +00:00
|
|
|
|
|
|
|
// Same, where public key is also encoded as text
|
|
|
|
//
|
|
|
|
int verify_string2(
|
2005-02-16 23:17:43 +00:00
|
|
|
const char* text, const char* signature_text, const char* key_text, bool& answer
|
2002-07-07 20:39:24 +00:00
|
|
|
) {
|
|
|
|
R_RSA_PUBLIC_KEY key;
|
|
|
|
int retval;
|
|
|
|
|
|
|
|
retval = sscan_key_hex(key_text, (KEY*)&key, sizeof(key));
|
|
|
|
if (retval) return retval;
|
|
|
|
return verify_string(text, signature_text, key, answer);
|
|
|
|
}
|
2003-09-03 05:42:33 +00:00
|
|
|
|
2005-02-16 23:17:43 +00:00
|
|
|
int read_key_file(const char* keyfile, R_RSA_PRIVATE_KEY& key) {
|
2003-09-03 05:42:33 +00:00
|
|
|
int retval;
|
2008-09-09 19:10:42 +00:00
|
|
|
#ifndef _USING_FCGI_
|
2003-09-03 05:42:33 +00:00
|
|
|
FILE* fkey = fopen(keyfile, "r");
|
2008-09-09 19:10:42 +00:00
|
|
|
#else
|
|
|
|
FCGI_FILE* fkey = FCGI::fopen(keyfile, "r");
|
|
|
|
#endif
|
2003-09-03 05:42:33 +00:00
|
|
|
if (!fkey) {
|
|
|
|
fprintf(stderr, "can't open key file (%s)\n", keyfile);
|
2003-10-21 04:06:55 +00:00
|
|
|
return ERR_FOPEN;
|
2003-09-03 05:42:33 +00:00
|
|
|
}
|
|
|
|
retval = scan_key_hex(fkey, (KEY*)&key, sizeof(key));
|
|
|
|
fclose(fkey);
|
|
|
|
if (retval) {
|
|
|
|
fprintf(stderr, "can't parse key\n");
|
2003-10-21 04:06:55 +00:00
|
|
|
return retval;
|
2003-09-03 05:42:33 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2004-12-08 00:40:19 +00:00
|
|
|
|
2005-08-01 22:44:40 +00:00
|
|
|
static void bn_to_bin(BIGNUM* bn, unsigned char* bin, int n) {
|
|
|
|
memset(bin, 0, n);
|
|
|
|
int m = BN_num_bytes(bn);
|
|
|
|
BN_bn2bin(bn, bin+n-m);
|
|
|
|
}
|
|
|
|
|
|
|
|
void openssl_to_keys(
|
|
|
|
RSA* rp, int nbits, R_RSA_PRIVATE_KEY& priv, R_RSA_PUBLIC_KEY& pub
|
|
|
|
) {
|
|
|
|
pub.bits = nbits;
|
|
|
|
bn_to_bin(rp->n, pub.modulus, sizeof(pub.modulus));
|
|
|
|
bn_to_bin(rp->e, pub.exponent, sizeof(pub.exponent));
|
|
|
|
|
|
|
|
memset(&priv, 0, sizeof(priv));
|
|
|
|
priv.bits = nbits;
|
|
|
|
bn_to_bin(rp->n, priv.modulus, sizeof(priv.modulus));
|
|
|
|
bn_to_bin(rp->e, priv.publicExponent, sizeof(priv.publicExponent));
|
|
|
|
bn_to_bin(rp->d, priv.exponent, sizeof(priv.exponent));
|
|
|
|
bn_to_bin(rp->p, priv.prime[0], sizeof(priv.prime[0]));
|
|
|
|
bn_to_bin(rp->q, priv.prime[1], sizeof(priv.prime[1]));
|
|
|
|
bn_to_bin(rp->dmp1, priv.primeExponent[0], sizeof(priv.primeExponent[0]));
|
|
|
|
bn_to_bin(rp->dmq1, priv.primeExponent[1], sizeof(priv.primeExponent[1]));
|
|
|
|
bn_to_bin(rp->iqmp, priv.coefficient, sizeof(priv.coefficient));
|
|
|
|
}
|
|
|
|
|
|
|
|
void private_to_openssl(R_RSA_PRIVATE_KEY& priv, RSA* rp) {
|
|
|
|
rp->n = BN_bin2bn(priv.modulus, sizeof(priv.modulus), 0);
|
|
|
|
rp->e = BN_bin2bn(priv.publicExponent, sizeof(priv.publicExponent), 0);
|
|
|
|
rp->d = BN_bin2bn(priv.exponent, sizeof(priv.exponent), 0);
|
|
|
|
rp->p = BN_bin2bn(priv.prime[0], sizeof(priv.prime[0]), 0);
|
|
|
|
rp->q = BN_bin2bn(priv.prime[1], sizeof(priv.prime[1]), 0);
|
|
|
|
rp->dmp1 = BN_bin2bn(priv.primeExponent[0], sizeof(priv.primeExponent[0]), 0);
|
|
|
|
rp->dmq1 = BN_bin2bn(priv.primeExponent[1], sizeof(priv.primeExponent[1]), 0);
|
|
|
|
rp->iqmp = BN_bin2bn(priv.coefficient, sizeof(priv.coefficient), 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void public_to_openssl(R_RSA_PUBLIC_KEY& pub, RSA* rp) {
|
|
|
|
rp->n = BN_bin2bn(pub.modulus, sizeof(pub.modulus), 0);
|
|
|
|
rp->e = BN_bin2bn(pub.exponent, sizeof(pub.exponent), 0);
|
|
|
|
}
|
|
|
|
|
2008-09-04 15:13:54 +00:00
|
|
|
static int _bn2bin(BIGNUM *from, unsigned char *to, int max) {
|
|
|
|
int i;
|
|
|
|
i=BN_num_bytes(from);
|
|
|
|
if (i > max) {
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
memset(to,0,(unsigned int)max);
|
|
|
|
if (!BN_bn2bin(from,&(to[max-i])))
|
|
|
|
return(0);
|
|
|
|
return(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
int openssl_to_private(RSA *from, R_RSA_PRIVATE_KEY *to) {
|
|
|
|
to->bits = BN_num_bits(from->n);
|
|
|
|
if (!_bn2bin(from->n,to->modulus,MAX_RSA_MODULUS_LEN))
|
|
|
|
return(0);
|
|
|
|
if (!_bn2bin(from->e,to->publicExponent,MAX_RSA_MODULUS_LEN))
|
|
|
|
return(0);
|
|
|
|
if (!_bn2bin(from->d,to->exponent,MAX_RSA_MODULUS_LEN))
|
|
|
|
return(0);
|
|
|
|
if (!_bn2bin(from->p,to->prime[0],MAX_RSA_PRIME_LEN))
|
|
|
|
return(0);
|
|
|
|
if (!_bn2bin(from->q,to->prime[1],MAX_RSA_PRIME_LEN))
|
|
|
|
return(0);
|
|
|
|
if (!_bn2bin(from->dmp1,to->primeExponent[0],MAX_RSA_PRIME_LEN))
|
|
|
|
return(0);
|
|
|
|
if (!_bn2bin(from->dmq1,to->primeExponent[1],MAX_RSA_PRIME_LEN))
|
|
|
|
return(0);
|
|
|
|
if (!_bn2bin(from->iqmp,to->coefficient,MAX_RSA_PRIME_LEN))
|
|
|
|
return(0);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int check_validity_of_cert(
|
|
|
|
const char *cFile, const unsigned char *md5_md, unsigned char *sfileMsg,
|
2008-09-24 23:42:56 +00:00
|
|
|
const int sfsize, const char* caPath
|
2008-09-04 15:13:54 +00:00
|
|
|
) {
|
2008-09-04 12:17:58 +00:00
|
|
|
int retval = 0;
|
|
|
|
X509 *cert;
|
|
|
|
X509_STORE *store;
|
|
|
|
X509_LOOKUP *lookup;
|
|
|
|
X509_STORE_CTX *ctx = 0;
|
|
|
|
EVP_PKEY *pubKey;
|
|
|
|
BIO *bio;
|
|
|
|
|
|
|
|
bio = BIO_new(BIO_s_file());
|
|
|
|
BIO_read_filename(bio, cFile);
|
|
|
|
if (NULL == (cert = PEM_read_bio_X509(bio, NULL, 0, NULL))) {
|
|
|
|
BIO_vfree(bio);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
// verify certificate
|
|
|
|
store = X509_STORE_new();
|
|
|
|
lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir());
|
|
|
|
X509_LOOKUP_add_dir(lookup, (char *)caPath, X509_FILETYPE_PEM);
|
|
|
|
if ((ctx = X509_STORE_CTX_new()) != 0) {
|
|
|
|
if (X509_STORE_CTX_init(ctx, store, cert, 0) == 1)
|
|
|
|
retval = X509_verify_cert(ctx);
|
|
|
|
X509_STORE_CTX_free(ctx);
|
|
|
|
}
|
|
|
|
X509_STORE_free(store);
|
|
|
|
|
|
|
|
if (retval != 1) {
|
|
|
|
fprintf(stderr,"ERROR: Cannot verify certificate ('%s')\n", cFile);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
pubKey = X509_get_pubkey(cert);
|
|
|
|
if (!pubKey) {
|
|
|
|
X509_free(cert);
|
|
|
|
BIO_vfree(bio);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (pubKey->type == EVP_PKEY_RSA) {
|
2009-06-04 23:03:47 +00:00
|
|
|
BN_CTX *c = BN_CTX_new();
|
|
|
|
if (!c) {
|
2008-09-04 12:17:58 +00:00
|
|
|
X509_free(cert);
|
|
|
|
EVP_PKEY_free(pubKey);
|
|
|
|
BIO_vfree(bio);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (!RSA_blinding_on(pubKey->pkey.rsa, c)) {
|
|
|
|
X509_free(cert);
|
|
|
|
EVP_PKEY_free(pubKey);
|
|
|
|
BIO_vfree(bio);
|
|
|
|
BN_CTX_free(c);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
retval = RSA_verify(NID_md5, md5_md, MD5_DIGEST_LENGTH, sfileMsg, sfsize, pubKey->pkey.rsa);
|
|
|
|
RSA_blinding_off(pubKey->pkey.rsa);
|
|
|
|
BN_CTX_free(c);
|
|
|
|
}
|
|
|
|
if (pubKey->type == EVP_PKEY_DSA) {
|
|
|
|
fprintf(stderr, "ERROR: DSA keys are not supported.\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
EVP_PKEY_free(pubKey);
|
|
|
|
X509_free(cert);
|
|
|
|
BIO_vfree(bio);
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2008-09-04 15:13:54 +00:00
|
|
|
char *check_validity(
|
|
|
|
const char *certPath, const char *origFile, unsigned char *signature,
|
|
|
|
char* caPath
|
|
|
|
) {
|
|
|
|
MD5_CTX md5CTX;
|
2008-09-09 19:10:42 +00:00
|
|
|
int rbytes;
|
2008-09-04 15:13:54 +00:00
|
|
|
unsigned char md5_md[MD5_DIGEST_LENGTH], rbuf[2048];
|
|
|
|
|
|
|
|
SSL_load_error_strings();
|
|
|
|
SSL_library_init();
|
|
|
|
|
|
|
|
if (!is_file(origFile)) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
FILE* of = boinc_fopen(origFile, "r");
|
|
|
|
if (!of) return NULL;
|
|
|
|
MD5_Init(&md5CTX);
|
2009-12-16 19:55:09 +00:00
|
|
|
while (0 != (rbytes = (int)fread(rbuf, 1, sizeof(rbuf), of))) {
|
2008-09-04 15:13:54 +00:00
|
|
|
MD5_Update(&md5CTX, rbuf, rbytes);
|
|
|
|
}
|
|
|
|
MD5_Final(md5_md, &md5CTX);
|
|
|
|
fclose(of);
|
|
|
|
|
|
|
|
DIRREF dir = dir_open(certPath);
|
|
|
|
|
|
|
|
char file[256];
|
|
|
|
while (dir_scan(file, dir, sizeof(file))) {
|
|
|
|
char fpath[512];
|
|
|
|
snprintf(fpath, sizeof(fpath), "%s/%s", certPath, file);
|
|
|
|
// TODO : replace '128'
|
|
|
|
if (check_validity_of_cert(fpath, md5_md, signature, 128, caPath)) {
|
|
|
|
dir_close(dir);
|
|
|
|
return strdup(fpath);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
dir_close(dir);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2008-09-04 12:50:54 +00:00
|
|
|
int cert_verify_file(
|
2008-09-24 23:42:56 +00:00
|
|
|
CERT_SIGS* signatures, const char* origFile, const char* trustLocation
|
2008-09-04 12:50:54 +00:00
|
|
|
) {
|
2008-09-04 12:17:58 +00:00
|
|
|
MD5_CTX md5CTX;
|
2008-09-04 13:18:51 +00:00
|
|
|
int rbytes;
|
2008-09-04 12:17:58 +00:00
|
|
|
unsigned char md5_md[MD5_DIGEST_LENGTH], rbuf[2048];
|
|
|
|
char buf[256];
|
|
|
|
char fbuf[512];
|
|
|
|
int verified = false;
|
|
|
|
int file_counter = 0;
|
|
|
|
DATA_BLOCK sig_db;
|
|
|
|
BIO *bio;
|
|
|
|
X509 *cert;
|
|
|
|
X509_NAME *subj;
|
|
|
|
|
|
|
|
if (signatures->signatures.size() == 0) {
|
|
|
|
printf("No signatures available for file ('%s').\n", origFile);
|
|
|
|
fflush(stdout);
|
|
|
|
return false;
|
|
|
|
}
|
2008-09-04 13:18:51 +00:00
|
|
|
SSL_library_init();
|
|
|
|
if (!is_file(origFile)) return false;
|
|
|
|
FILE* of = boinc_fopen(origFile, "r");
|
|
|
|
if (!of) return false;
|
2008-09-04 12:17:58 +00:00
|
|
|
MD5_Init(&md5CTX);
|
2009-12-16 19:55:09 +00:00
|
|
|
while (0 != (rbytes = (int)fread(rbuf, 1, sizeof(rbuf), of))) {
|
2008-09-04 12:17:58 +00:00
|
|
|
MD5_Update(&md5CTX, rbuf, rbytes);
|
2008-09-04 13:18:51 +00:00
|
|
|
}
|
2008-09-04 12:17:58 +00:00
|
|
|
MD5_Final(md5_md, &md5CTX);
|
2008-09-04 13:18:51 +00:00
|
|
|
fclose(of);
|
|
|
|
for(unsigned int i=0;i < signatures->signatures.size(); i++) {
|
2008-09-04 12:17:58 +00:00
|
|
|
sig_db.data = (unsigned char*)calloc(128, sizeof(char));
|
|
|
|
if (sig_db.data == NULL) {
|
|
|
|
printf("Cannot allocate 128 bytes for signature buffer\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
sig_db.len=128;
|
|
|
|
sscan_hex_data(signatures->signatures.at(i).signature, sig_db);
|
|
|
|
file_counter = 0;
|
|
|
|
while (1) {
|
|
|
|
snprintf(fbuf, 512, "%s/%s.%d", trustLocation, signatures->signatures.at(i).hash,
|
|
|
|
file_counter);
|
2008-09-09 19:10:42 +00:00
|
|
|
#ifndef _USING_FCGI_
|
|
|
|
FILE *f = fopen(fbuf, "r");
|
|
|
|
#else
|
|
|
|
FCGI_FILE *f = FCGI::fopen(fbuf, "r");
|
|
|
|
#endif
|
2008-09-04 12:17:58 +00:00
|
|
|
if (f==NULL)
|
|
|
|
break;
|
|
|
|
fclose(f);
|
|
|
|
bio = BIO_new(BIO_s_file());
|
|
|
|
BIO_read_filename(bio, fbuf);
|
|
|
|
if (NULL == (cert = PEM_read_bio_X509(bio, NULL, 0, NULL))) {
|
|
|
|
BIO_vfree(bio);
|
|
|
|
printf("Cannot read certificate ('%s')\n", fbuf);
|
|
|
|
file_counter++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
fflush(stdout);
|
|
|
|
subj = X509_get_subject_name(cert);
|
|
|
|
X509_NAME_oneline(subj, buf, 256);
|
|
|
|
// ???
|
|
|
|
//X509_NAME_free(subj);
|
|
|
|
X509_free(cert);
|
|
|
|
BIO_vfree(bio);
|
|
|
|
if (strcmp(buf, signatures->signatures.at(i).subject)) {
|
|
|
|
printf("Subject does not match ('%s' <-> '%s')\n", buf, signatures->signatures.at(i).subject);
|
|
|
|
file_counter++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
verified = check_validity_of_cert(fbuf, md5_md, sig_db.data, 128, trustLocation);
|
|
|
|
if (verified)
|
|
|
|
break;
|
|
|
|
file_counter++;
|
|
|
|
}
|
|
|
|
free(sig_db.data);
|
|
|
|
if (!verified)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return verified;
|
|
|
|
}
|
|
|
|
|