remove pssl-{openssl,securetransport}.c
This commit is contained in:
parent
2e702d8d4e
commit
4a70d57cd3
|
|
@ -1,989 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright (c) 2013 Anton Titov.
|
|
||||||
|
|
||||||
Copyright (c) 2013 pCloud Ltd. All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions
|
|
||||||
are met: Redistributions of source code must retain the above
|
|
||||||
copyright notice, this list of conditions and the following
|
|
||||||
disclaimer. Redistributions in binary form must reproduce the
|
|
||||||
above copyright notice, this list of conditions and the following
|
|
||||||
disclaimer in the documentation and/or other materials provided
|
|
||||||
with the distribution. Neither the name of pCloud Ltd nor the
|
|
||||||
names of its contributors may be used to endorse or promote
|
|
||||||
products derived from this software without specific prior written
|
|
||||||
permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
||||||
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL pCloud
|
|
||||||
Ltd BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
||||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
|
||||||
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
|
||||||
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
|
||||||
DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "plibs.h"
|
|
||||||
#include "pssl.h"
|
|
||||||
#include "psynclib.h"
|
|
||||||
#include "psslcerts.h"
|
|
||||||
#include "psettings.h"
|
|
||||||
#include "pcache.h"
|
|
||||||
#include "ptimer.h"
|
|
||||||
#include "pmemlock.h"
|
|
||||||
#include <openssl/ssl.h>
|
|
||||||
#include <openssl/rand.h>
|
|
||||||
#include <openssl/err.h>
|
|
||||||
#include <pthread.h>
|
|
||||||
|
|
||||||
#define SSL_CIPHERS \
|
|
||||||
"ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:"\
|
|
||||||
"DHE-RSA-AES256-GCM-SHA384:ECDH-RSA-AES256-GCM-SHA384:"\
|
|
||||||
"ECDHE-RSA-AES256-SHA384:DHE-RSA-AES256-SHA256:"\
|
|
||||||
"AES256-GCM-SHA384:AES256-SHA256;"
|
|
||||||
|
|
||||||
|
|
||||||
#if defined(PSYNC_AES_HW_MSC)
|
|
||||||
#include <intrin.h>
|
|
||||||
#include <wmmintrin.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
SSL *ssl;
|
|
||||||
int isbroken;
|
|
||||||
char cachekey[];
|
|
||||||
} ssl_connection_t;
|
|
||||||
|
|
||||||
static SSL_CTX *globalctx=NULL;
|
|
||||||
static pthread_mutex_t *olocks;
|
|
||||||
|
|
||||||
#if defined(PSYNC_AES_HW)
|
|
||||||
int psync_ssl_hw_aes;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
PSYNC_THREAD int psync_ssl_errno;
|
|
||||||
|
|
||||||
static void openssl_locking_callback(int mode, int type, const char *file, int line){
|
|
||||||
if (mode&CRYPTO_LOCK)
|
|
||||||
pthread_mutex_lock(&(olocks[type]));
|
|
||||||
else
|
|
||||||
pthread_mutex_unlock(&(olocks[type]));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void openssl_thread_id(CRYPTO_THREADID *id){
|
|
||||||
CRYPTO_THREADID_set_pointer(id, &psync_ssl_errno);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int openssl_locking_default(int *num, int cnt, int type, const char *file, int line){
|
|
||||||
openssl_locking_callback(CRYPTO_LOCK|CRYPTO_WRITE, type, file, line);
|
|
||||||
cnt+=*num;
|
|
||||||
*num=cnt;
|
|
||||||
openssl_locking_callback(CRYPTO_UNLOCK|CRYPTO_WRITE, type, file, line);
|
|
||||||
return cnt;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int openssl_locking_add(int *num, int cnt, int type, const char *file, int line){
|
|
||||||
#if defined(P_OS_WINDOWS)
|
|
||||||
if (sizeof(LONG)==sizeof(int))
|
|
||||||
return _InterlockedAdd(num, cnt);
|
|
||||||
else
|
|
||||||
return openssl_locking_default(num, cnt, type, file, line);
|
|
||||||
#elif defined(__GNUC__)
|
|
||||||
if (1)
|
|
||||||
return __sync_add_and_fetch(num, cnt);
|
|
||||||
else
|
|
||||||
return openssl_locking_default(num, cnt, type, file, line);
|
|
||||||
#else
|
|
||||||
return openssl_locking_default(num, cnt, type, file, line);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static void openssl_thread_setup(){
|
|
||||||
int i, n;
|
|
||||||
n=CRYPTO_num_locks();
|
|
||||||
olocks=psync_new_cnt(pthread_mutex_t, n);
|
|
||||||
for (i=0; i<n; i++)
|
|
||||||
pthread_mutex_init(&olocks[i], NULL);
|
|
||||||
CRYPTO_THREADID_set_callback(openssl_thread_id);
|
|
||||||
CRYPTO_set_locking_callback(openssl_locking_callback);
|
|
||||||
CRYPTO_set_add_lock_callback(openssl_locking_add);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(PSYNC_AES_HW_GCC)
|
|
||||||
static int psync_ssl_detect_aes_hw(){
|
|
||||||
uint32_t eax, ecx;
|
|
||||||
eax=1;
|
|
||||||
__asm__("cpuid"
|
|
||||||
: "=c"(ecx)
|
|
||||||
: "a"(eax)
|
|
||||||
: "%ebx", "%edx");
|
|
||||||
ecx=(ecx>>25)&1;
|
|
||||||
if (ecx)
|
|
||||||
debug(D_NOTICE, "hardware AES support detected");
|
|
||||||
else
|
|
||||||
debug(D_NOTICE, "hardware AES support not detected");
|
|
||||||
return ecx;
|
|
||||||
}
|
|
||||||
#elif defined(PSYNC_AES_HW_MSC)
|
|
||||||
static int psync_ssl_detect_aes_hw(){
|
|
||||||
int info[4];
|
|
||||||
int ret;
|
|
||||||
__cpuid(info, 1);
|
|
||||||
ret=(info[2]>>25)&1;
|
|
||||||
if (ret)
|
|
||||||
debug(D_NOTICE, "hardware AES support detected");
|
|
||||||
else
|
|
||||||
debug(D_NOTICE, "hardware AES support not detected");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int psync_ssl_init(){
|
|
||||||
BIO *bio;
|
|
||||||
X509 *cert;
|
|
||||||
psync_uint_t i;
|
|
||||||
unsigned char seed[PSYNC_LHASH_DIGEST_LEN];
|
|
||||||
#if defined(PSYNC_AES_HW)
|
|
||||||
psync_ssl_hw_aes=psync_ssl_detect_aes_hw();
|
|
||||||
#else
|
|
||||||
debug(D_NOTICE, "hardware AES is not supported for this compiler");
|
|
||||||
#endif
|
|
||||||
if (!CRYPTO_set_locked_mem_functions(psync_locked_malloc, psync_locked_free))
|
|
||||||
debug(D_WARNING, "failed to set locked functions for OpenSSL");
|
|
||||||
SSL_library_init();
|
|
||||||
OpenSSL_add_all_algorithms();
|
|
||||||
OpenSSL_add_all_ciphers();
|
|
||||||
SSL_load_error_strings();
|
|
||||||
openssl_thread_setup();
|
|
||||||
globalctx=SSL_CTX_new(TLSv1_2_client_method());
|
|
||||||
if (likely_log(globalctx)){
|
|
||||||
if (unlikely_log(SSL_CTX_set_cipher_list(globalctx, SSL_CIPHERS)!=1)){
|
|
||||||
SSL_CTX_free(globalctx);
|
|
||||||
globalctx=NULL;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
SSL_CTX_set_verify(globalctx, SSL_VERIFY_NONE, NULL);
|
|
||||||
SSL_CTX_set_read_ahead(globalctx, 0); // readahed breaks SSL_Pending
|
|
||||||
SSL_CTX_set_session_cache_mode(globalctx, SSL_SESS_CACHE_CLIENT|SSL_SESS_CACHE_NO_INTERNAL);
|
|
||||||
SSL_CTX_set_options(globalctx, SSL_OP_NO_COMPRESSION);
|
|
||||||
SSL_CTX_set_mode(globalctx, SSL_MODE_RELEASE_BUFFERS);
|
|
||||||
SSL_CTX_set_mode(globalctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
|
|
||||||
for (i=0; i<ARRAY_SIZE(psync_ssl_trusted_certs); i++){
|
|
||||||
bio=BIO_new(BIO_s_mem());
|
|
||||||
BIO_puts(bio, psync_ssl_trusted_certs[i]);
|
|
||||||
cert=PEM_read_bio_X509(bio, NULL, NULL, NULL);
|
|
||||||
BIO_free(bio);
|
|
||||||
if (likely_log(cert!=NULL)){
|
|
||||||
X509_STORE_add_cert(SSL_CTX_get_cert_store(globalctx), cert);
|
|
||||||
X509_free(cert);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
psync_get_random_seed(seed, NULL, 0, 0);
|
|
||||||
RAND_seed(seed, PSYNC_LHASH_DIGEST_LEN);
|
|
||||||
} while (!RAND_status());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void psync_ssl_memclean(void *ptr, size_t len){
|
|
||||||
OPENSSL_cleanse(ptr, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void psync_set_ssl_error(ssl_connection_t *conn, int err){
|
|
||||||
if (err==SSL_ERROR_WANT_READ)
|
|
||||||
psync_ssl_errno=PSYNC_SSL_ERR_WANT_READ;
|
|
||||||
else if (err==SSL_ERROR_WANT_WRITE)
|
|
||||||
psync_ssl_errno=PSYNC_SSL_ERR_WANT_WRITE;
|
|
||||||
else{
|
|
||||||
psync_ssl_errno=PSYNC_SSL_ERR_UNKNOWN;
|
|
||||||
conn->isbroken=1;
|
|
||||||
debug(D_NOTICE, "got error %d from OpenSSL: %s", err, ERR_error_string(err, NULL));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns non-zero when CN and hostname match.
|
|
||||||
// Does case sensititive comparison, fine for now. Replace memcmp with str(n)casecmp if case insensitivity is needed
|
|
||||||
static int psync_ssl_compare_cn_hostname(const char *cn, size_t cnlen, const char *hostname, size_t hostnamelen){
|
|
||||||
if (cn[0]=='*' && cn[1]=='.') // assumes valid null terminated string
|
|
||||||
return cnlen<=hostnamelen &&
|
|
||||||
!memcmp(cn+1, hostname+hostnamelen-cnlen+1, cnlen) && //this will also compare the null byte
|
|
||||||
!memchr(hostname, '.', hostnamelen-cnlen+1);
|
|
||||||
else
|
|
||||||
return cnlen==hostnamelen && !memcmp(cn, hostname, cnlen);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int psync_ssl_cn_match_hostname(X509 *cert, const char *hostname){
|
|
||||||
X509_NAME *sname;
|
|
||||||
X509_NAME_ENTRY *cnentry;
|
|
||||||
ASN1_STRING *cnasn;
|
|
||||||
const char *cnstr;
|
|
||||||
size_t cnstrlen;
|
|
||||||
int idx;
|
|
||||||
sname=X509_get_subject_name(cert);
|
|
||||||
if (unlikely_log(!sname))
|
|
||||||
return -1;
|
|
||||||
idx=X509_NAME_get_index_by_NID(sname, NID_commonName, -1);
|
|
||||||
if (unlikely_log(idx<0))
|
|
||||||
return -1;
|
|
||||||
cnentry=X509_NAME_get_entry(sname, idx);
|
|
||||||
if (unlikely_log(!cnentry))
|
|
||||||
return -1;
|
|
||||||
cnasn=X509_NAME_ENTRY_get_data(cnentry);
|
|
||||||
if (unlikely_log(!cnasn))
|
|
||||||
return -1;
|
|
||||||
cnstr=(const char *)ASN1_STRING_data(cnasn);
|
|
||||||
if (unlikely_log(!cnstr))
|
|
||||||
return -1;
|
|
||||||
cnstrlen=strlen(cnstr);
|
|
||||||
if (unlikely_log(ASN1_STRING_length(cnasn)!=cnstrlen))
|
|
||||||
return -1;
|
|
||||||
debug(D_NOTICE, "got certificate with commonName: %s", cnstr);
|
|
||||||
if (psync_ssl_compare_cn_hostname(cnstr, cnstrlen, hostname, strlen(hostname)))
|
|
||||||
return 0;
|
|
||||||
else{
|
|
||||||
debug(D_WARNING, "hostname %s does not match certificate common name %s", hostname, cnstr);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int psync_ssl_verify_cert(SSL *ssl, const char *hostname){
|
|
||||||
X509 *cert;
|
|
||||||
int ret;
|
|
||||||
if (unlikely_log(SSL_get_verify_result(ssl)!=X509_V_OK))
|
|
||||||
return -1;
|
|
||||||
cert=SSL_get_peer_certificate(ssl);
|
|
||||||
if (unlikely_log(!cert))
|
|
||||||
return -1;
|
|
||||||
ret=psync_ssl_cn_match_hostname(cert, hostname);
|
|
||||||
X509_free(cert);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssl_connection_t *psync_ssl_alloc_conn(SSL *ssl, const char *hostname){
|
|
||||||
ssl_connection_t *conn;
|
|
||||||
size_t len;
|
|
||||||
len=strlen(hostname)+1;
|
|
||||||
conn=(ssl_connection_t *)psync_malloc(offsetof(ssl_connection_t, cachekey)+len+4);
|
|
||||||
conn->ssl=ssl;
|
|
||||||
conn->isbroken=0;
|
|
||||||
memcpy(conn->cachekey, "SSLS", 4);
|
|
||||||
memcpy(conn->cachekey+4, hostname, len);
|
|
||||||
return conn;
|
|
||||||
}
|
|
||||||
|
|
||||||
int psync_ssl_connect(psync_socket_t sock, void **sslconn, const char *hostname){
|
|
||||||
ssl_connection_t *conn;
|
|
||||||
SSL *ssl;
|
|
||||||
SSL_SESSION *sess;
|
|
||||||
int res, err;
|
|
||||||
ssl=SSL_new(globalctx);
|
|
||||||
if (!ssl)
|
|
||||||
return PRINT_RETURN_CONST(PSYNC_SSL_FAIL);
|
|
||||||
SSL_set_fd(ssl, sock);
|
|
||||||
conn=psync_ssl_alloc_conn(ssl, hostname);
|
|
||||||
if ((sess=(SSL_SESSION *)psync_cache_get(conn->cachekey))){
|
|
||||||
debug(D_NOTICE, "reusing cached session for %s", hostname);
|
|
||||||
SSL_set_session(ssl, sess);
|
|
||||||
SSL_SESSION_free(sess);
|
|
||||||
}
|
|
||||||
res=SSL_connect(ssl);
|
|
||||||
if (res==1){
|
|
||||||
if (unlikely(psync_ssl_verify_cert(ssl, hostname)))
|
|
||||||
goto fail;
|
|
||||||
*sslconn=conn;
|
|
||||||
if (IS_DEBUG && SSL_session_reused(ssl))
|
|
||||||
debug(D_NOTICE, "successfully reused session");
|
|
||||||
return PSYNC_SSL_SUCCESS;
|
|
||||||
}
|
|
||||||
err=SSL_get_error(ssl, res);
|
|
||||||
psync_set_ssl_error(conn, err);
|
|
||||||
if (likely_log(err==SSL_ERROR_WANT_READ || err==SSL_ERROR_WANT_WRITE)){
|
|
||||||
*sslconn=conn;
|
|
||||||
return PSYNC_SSL_NEED_FINISH;
|
|
||||||
}
|
|
||||||
fail:
|
|
||||||
SSL_free(ssl);
|
|
||||||
psync_free(conn);
|
|
||||||
return PRINT_RETURN_CONST(PSYNC_SSL_FAIL);
|
|
||||||
}
|
|
||||||
|
|
||||||
int psync_ssl_connect_finish(void *sslconn, const char *hostname){
|
|
||||||
ssl_connection_t *conn;
|
|
||||||
int res, err;
|
|
||||||
conn=(ssl_connection_t *)sslconn;
|
|
||||||
res=SSL_connect(conn->ssl);
|
|
||||||
if (res==1){
|
|
||||||
if (unlikely(psync_ssl_verify_cert(conn->ssl, hostname)))
|
|
||||||
goto fail;
|
|
||||||
if (IS_DEBUG && SSL_session_reused(conn->ssl))
|
|
||||||
debug(D_NOTICE, "successfully reused session");
|
|
||||||
return PSYNC_SSL_SUCCESS;
|
|
||||||
}
|
|
||||||
err=SSL_get_error(conn->ssl, res);
|
|
||||||
psync_set_ssl_error(conn, err);
|
|
||||||
if (likely_log(err==SSL_ERROR_WANT_READ || err==SSL_ERROR_WANT_WRITE))
|
|
||||||
return PSYNC_SSL_NEED_FINISH;
|
|
||||||
fail:
|
|
||||||
SSL_free(conn->ssl);
|
|
||||||
psync_free(conn);
|
|
||||||
return PRINT_RETURN_CONST(PSYNC_SSL_FAIL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void psync_ssl_free_session(void *ptr){
|
|
||||||
SSL_SESSION_free((SSL_SESSION *)ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
int psync_ssl_shutdown(void *sslconn){
|
|
||||||
ssl_connection_t *conn;
|
|
||||||
SSL_SESSION *sess;
|
|
||||||
int res, err;
|
|
||||||
conn=(ssl_connection_t *)sslconn;
|
|
||||||
sess=SSL_get1_session(conn->ssl);
|
|
||||||
if (sess)
|
|
||||||
psync_cache_add(conn->cachekey, sess, PSYNC_SSL_SESSION_CACHE_TIMEOUT, psync_ssl_free_session, PSYNC_MAX_SSL_SESSIONS_PER_DOMAIN);
|
|
||||||
if (conn->isbroken)
|
|
||||||
goto noshutdown;
|
|
||||||
res=SSL_shutdown(conn->ssl);
|
|
||||||
if (res!=-1)
|
|
||||||
goto noshutdown;
|
|
||||||
err=SSL_get_error(conn->ssl, res);
|
|
||||||
psync_set_ssl_error(conn, err);
|
|
||||||
if (likely_log(err==SSL_ERROR_WANT_READ || err==SSL_ERROR_WANT_WRITE))
|
|
||||||
return PSYNC_SSL_NEED_FINISH;
|
|
||||||
noshutdown:
|
|
||||||
SSL_free(conn->ssl);
|
|
||||||
psync_free(conn);
|
|
||||||
return PSYNC_SSL_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
void psync_ssl_free(void *sslconn){
|
|
||||||
ssl_connection_t *conn;
|
|
||||||
conn=(ssl_connection_t *)sslconn;
|
|
||||||
SSL_free(conn->ssl);
|
|
||||||
psync_free(conn);
|
|
||||||
}
|
|
||||||
|
|
||||||
int psync_ssl_pendingdata(void *sslconn){
|
|
||||||
return SSL_pending(((ssl_connection_t *)sslconn)->ssl);
|
|
||||||
}
|
|
||||||
|
|
||||||
int psync_ssl_read(void *sslconn, void *buf, int num){
|
|
||||||
ssl_connection_t *conn;
|
|
||||||
int res, err;
|
|
||||||
conn=(ssl_connection_t *)sslconn;
|
|
||||||
res=SSL_read(conn->ssl, buf, num);
|
|
||||||
if (res>=0)
|
|
||||||
return res;
|
|
||||||
err=SSL_get_error(conn->ssl, res);
|
|
||||||
psync_set_ssl_error(conn, err);
|
|
||||||
return PSYNC_SSL_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int psync_ssl_write(void *sslconn, const void *buf, int num){
|
|
||||||
ssl_connection_t *conn;
|
|
||||||
int res, err;
|
|
||||||
conn=(ssl_connection_t *)sslconn;
|
|
||||||
res=SSL_write(conn->ssl, buf, num);
|
|
||||||
if (res>=0)
|
|
||||||
return res;
|
|
||||||
err=SSL_get_error(conn->ssl, res);
|
|
||||||
psync_set_ssl_error(conn, err);
|
|
||||||
return PSYNC_SSL_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void psync_ssl_rand_strong(unsigned char *buf, int num){
|
|
||||||
static int seeds=0;
|
|
||||||
int ret;
|
|
||||||
if (seeds<2){
|
|
||||||
unsigned char seed[PSYNC_LHASH_DIGEST_LEN];
|
|
||||||
psync_get_random_seed(seed, buf, num, 1);
|
|
||||||
RAND_seed(seed, PSYNC_LHASH_DIGEST_LEN);
|
|
||||||
seeds++;
|
|
||||||
}
|
|
||||||
ret=RAND_bytes(buf, num);
|
|
||||||
if (unlikely(ret==0)){
|
|
||||||
unsigned char seed[PSYNC_LHASH_DIGEST_LEN];
|
|
||||||
psync_uint_t cnt;
|
|
||||||
cnt=0;
|
|
||||||
while (ret==0 && cnt++<20){
|
|
||||||
psync_get_random_seed(seed, NULL, 0, 0);
|
|
||||||
RAND_seed(seed, PSYNC_LHASH_DIGEST_LEN);
|
|
||||||
ret=RAND_bytes(buf, num);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (unlikely(ret!=1)){
|
|
||||||
debug(D_CRITICAL, "could not generate %d random bytes, error %s, exiting", num, ERR_error_string(ERR_get_error(), NULL));
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void psync_ssl_rand_weak(unsigned char *buf, int num){
|
|
||||||
int ret;
|
|
||||||
ret=RAND_pseudo_bytes(buf, num);
|
|
||||||
if (unlikely(ret==-1)){
|
|
||||||
debug(D_CRITICAL, "could not generate %d weak random bytes, error %s, exiting", num, ERR_error_string(ERR_get_error(), NULL));
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
else if (unlikely(ret==0))
|
|
||||||
debug(D_WARNING, "RAND_pseudo_bytes returned weak numbers");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* this function comes from OpenSSL's crypto/rsa/rsa_lib.c, this version is not (that) buggy and reformatted */
|
|
||||||
static int RSA_memory_lock_fixed(RSA *r){
|
|
||||||
int i, j, k, off;
|
|
||||||
char *p;
|
|
||||||
BIGNUM *bn, **t[6], *b;
|
|
||||||
BN_ULONG *ul;
|
|
||||||
if (r->d==NULL)
|
|
||||||
return 1;
|
|
||||||
t[0]=&r->d;
|
|
||||||
t[1]=&r->p;
|
|
||||||
t[2]=&r->q;
|
|
||||||
t[3]=&r->dmp1;
|
|
||||||
t[4]=&r->dmq1;
|
|
||||||
t[5]=&r->iqmp;
|
|
||||||
k=sizeof(BIGNUM)*6;
|
|
||||||
off=k/sizeof(BN_ULONG)+1;
|
|
||||||
j=1;
|
|
||||||
for (i=0; i<6; i++)
|
|
||||||
j+=(*t[i])->top;
|
|
||||||
if ((p=OPENSSL_malloc_locked((off+j)*sizeof(BN_ULONG)))==NULL){
|
|
||||||
RSAerr(RSA_F_RSA_MEMORY_LOCK, ERR_R_MALLOC_FAILURE);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
bn=(BIGNUM *)p;
|
|
||||||
ul=(BN_ULONG *)&p[k];
|
|
||||||
for (i=0; i<6; i++){
|
|
||||||
b= *(t[i]);
|
|
||||||
*(t[i])= &(bn[i]);
|
|
||||||
memcpy((char *)&(bn[i]), (char *)b, sizeof(BIGNUM));
|
|
||||||
bn[i].flags=BN_FLG_STATIC_DATA;
|
|
||||||
bn[i].d=ul;
|
|
||||||
memcpy((char *)ul, b->d, sizeof(BN_ULONG)*b->top);
|
|
||||||
ul+=b->top;
|
|
||||||
BN_clear_free(b);
|
|
||||||
}
|
|
||||||
r->flags&=~(RSA_FLAG_CACHE_PRIVATE|RSA_FLAG_CACHE_PUBLIC);
|
|
||||||
r->bignum_data=p;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
psync_rsa_t psync_ssl_gen_rsa(int bits){
|
|
||||||
RSA *rsa;
|
|
||||||
BIGNUM *bn;
|
|
||||||
unsigned char seed[PSYNC_LHASH_DIGEST_LEN];
|
|
||||||
psync_get_random_seed(seed, seed, sizeof(seed), 0);
|
|
||||||
RAND_seed(seed, PSYNC_LHASH_DIGEST_LEN);
|
|
||||||
rsa=RSA_new();
|
|
||||||
if (unlikely_log(!rsa))
|
|
||||||
goto err0;
|
|
||||||
bn=BN_new();
|
|
||||||
if (unlikely_log(!bn))
|
|
||||||
goto err1;
|
|
||||||
if (unlikely_log(!BN_set_word(bn, RSA_F4)))
|
|
||||||
goto err2;
|
|
||||||
if (unlikely_log(!RSA_generate_key_ex(rsa, bits, bn, NULL)))
|
|
||||||
goto err2;
|
|
||||||
RSA_memory_lock_fixed(rsa);
|
|
||||||
BN_free(bn);
|
|
||||||
return rsa;
|
|
||||||
err2:
|
|
||||||
BN_free(bn);
|
|
||||||
err1:
|
|
||||||
RSA_free(rsa);
|
|
||||||
err0:
|
|
||||||
return PSYNC_INVALID_RSA;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void psync_ssl_lock_rsa(RSA *rsa){
|
|
||||||
RSA_memory_lock_fixed(rsa);
|
|
||||||
}
|
|
||||||
|
|
||||||
void psync_ssl_free_rsa(psync_rsa_t rsa){
|
|
||||||
RSA_free(rsa);
|
|
||||||
}
|
|
||||||
|
|
||||||
psync_rsa_publickey_t psync_ssl_rsa_get_public(psync_rsa_t rsa){
|
|
||||||
return RSAPublicKey_dup(rsa);
|
|
||||||
}
|
|
||||||
|
|
||||||
void psync_ssl_rsa_free_public(psync_rsa_publickey_t key){
|
|
||||||
RSA_free(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
psync_rsa_privatekey_t psync_ssl_rsa_get_private(psync_rsa_t rsa){
|
|
||||||
RSA *rsap=RSAPrivateKey_dup(rsa);
|
|
||||||
if (rsap)
|
|
||||||
psync_ssl_lock_rsa(rsap);
|
|
||||||
return rsap;
|
|
||||||
}
|
|
||||||
|
|
||||||
void psync_ssl_rsa_free_private(psync_rsa_privatekey_t key){
|
|
||||||
RSA_free(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
psync_binary_rsa_key_t psync_ssl_rsa_public_to_binary(psync_rsa_publickey_t rsa){
|
|
||||||
psync_binary_rsa_key_t ret;
|
|
||||||
unsigned char *p;
|
|
||||||
int len;
|
|
||||||
len=i2d_RSAPublicKey(rsa, NULL);
|
|
||||||
if (unlikely_log(len<0))
|
|
||||||
return PSYNC_INVALID_BIN_RSA;
|
|
||||||
ret=psync_locked_malloc(offsetof(psync_encrypted_data_struct_t, data)+len);
|
|
||||||
ret->datalen=len;
|
|
||||||
p=ret->data;
|
|
||||||
if (unlikely_log(i2d_RSAPublicKey(rsa, &p)!=len)){
|
|
||||||
psync_locked_free(ret);
|
|
||||||
return PSYNC_INVALID_BIN_RSA;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
psync_binary_rsa_key_t psync_ssl_rsa_private_to_binary(psync_rsa_privatekey_t rsa){
|
|
||||||
psync_binary_rsa_key_t ret;
|
|
||||||
unsigned char *p;
|
|
||||||
int len;
|
|
||||||
len=i2d_RSAPrivateKey(rsa, NULL);
|
|
||||||
if (unlikely_log(len<0))
|
|
||||||
return PSYNC_INVALID_BIN_RSA;
|
|
||||||
ret=psync_locked_malloc(offsetof(psync_encrypted_data_struct_t, data)+len);
|
|
||||||
ret->datalen=len;
|
|
||||||
p=ret->data;
|
|
||||||
if (unlikely_log(i2d_RSAPrivateKey(rsa, &p)!=len)){
|
|
||||||
psync_locked_free(ret);
|
|
||||||
return PSYNC_INVALID_BIN_RSA;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
psync_rsa_publickey_t psync_ssl_rsa_load_public(const unsigned char *keydata, size_t keylen){
|
|
||||||
return d2i_RSAPublicKey(NULL, &keydata, keylen);
|
|
||||||
}
|
|
||||||
|
|
||||||
psync_rsa_privatekey_t psync_ssl_rsa_load_private(const unsigned char *keydata, size_t keylen){
|
|
||||||
RSA *rsa=d2i_RSAPrivateKey(NULL, &keydata, keylen);
|
|
||||||
if (rsa)
|
|
||||||
psync_ssl_lock_rsa(rsa);
|
|
||||||
return rsa;
|
|
||||||
}
|
|
||||||
|
|
||||||
psync_rsa_publickey_t psync_ssl_rsa_binary_to_public(psync_binary_rsa_key_t bin){
|
|
||||||
return psync_ssl_rsa_load_public(bin->data, bin->datalen);
|
|
||||||
}
|
|
||||||
|
|
||||||
psync_rsa_privatekey_t psync_ssl_rsa_binary_to_private(psync_binary_rsa_key_t bin){
|
|
||||||
return psync_ssl_rsa_load_private(bin->data, bin->datalen);
|
|
||||||
}
|
|
||||||
|
|
||||||
psync_symmetric_key_t psync_ssl_gen_symmetric_key_from_pass(const char *password, size_t keylen, const unsigned char *salt, size_t saltlen, size_t iterations){
|
|
||||||
psync_symmetric_key_t key=(psync_symmetric_key_t)psync_locked_malloc(keylen+offsetof(psync_symmetric_key_struct_t, key));
|
|
||||||
key->keylen=keylen;
|
|
||||||
PKCS5_PBKDF2_HMAC(password, strlen(password), salt,
|
|
||||||
saltlen, iterations, EVP_sha512(), keylen, key->key);
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
psync_encrypted_symmetric_key_t psync_ssl_rsa_encrypt_data(psync_rsa_publickey_t rsa, const unsigned char *data, size_t datalen){
|
|
||||||
psync_encrypted_symmetric_key_t ret;
|
|
||||||
int len;
|
|
||||||
ret=(psync_encrypted_symmetric_key_t)psync_malloc(offsetof(psync_encrypted_data_struct_t, data)+RSA_size(rsa));
|
|
||||||
len=RSA_public_encrypt(datalen, data, ret->data, rsa, RSA_PKCS1_OAEP_PADDING);
|
|
||||||
if (unlikely_log(len==-1)){
|
|
||||||
psync_free(ret);
|
|
||||||
return PSYNC_INVALID_ENC_SYM_KEY;
|
|
||||||
}
|
|
||||||
ret->datalen=len;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
psync_symmetric_key_t psync_ssl_rsa_decrypt_data(psync_rsa_privatekey_t rsa, const unsigned char *data, size_t datalen){
|
|
||||||
unsigned char buff[2048];
|
|
||||||
psync_symmetric_key_t ret;
|
|
||||||
int len;
|
|
||||||
len=RSA_private_decrypt(datalen, data, buff, rsa, RSA_PKCS1_OAEP_PADDING);
|
|
||||||
if (unlikely(len==-1)){
|
|
||||||
#if IS_DEBUG
|
|
||||||
unsigned long e;
|
|
||||||
e=ERR_get_error();
|
|
||||||
debug(D_WARNING, "could not decrypt key, RSA_private_decrypt returned error %lu: %s", e, ERR_error_string(e, (char *)buff));
|
|
||||||
#endif
|
|
||||||
return PSYNC_INVALID_SYM_KEY;
|
|
||||||
}
|
|
||||||
ret=(psync_symmetric_key_t)psync_locked_malloc(offsetof(psync_symmetric_key_struct_t, key)+len);
|
|
||||||
ret->keylen=len;
|
|
||||||
memcpy(ret->key, buff, len);
|
|
||||||
psync_ssl_memclean(buff, len);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
psync_encrypted_symmetric_key_t psync_ssl_rsa_encrypt_symmetric_key(psync_rsa_publickey_t rsa, const psync_symmetric_key_t key){
|
|
||||||
return psync_ssl_rsa_encrypt_data(rsa, key->key, key->keylen);
|
|
||||||
}
|
|
||||||
|
|
||||||
psync_symmetric_key_t psync_ssl_rsa_decrypt_symmetric_key(psync_rsa_privatekey_t rsa, const psync_encrypted_symmetric_key_t enckey){
|
|
||||||
return psync_ssl_rsa_decrypt_data(rsa, enckey->data, enckey->datalen);
|
|
||||||
}
|
|
||||||
|
|
||||||
static AES_KEY *psync_ssl_get_aligned_aes_key(){
|
|
||||||
unsigned char *m, *a;
|
|
||||||
m=(unsigned char *)psync_locked_malloc(PSYNC_AES256_BLOCK_SIZE+sizeof(AES_KEY));
|
|
||||||
a=(unsigned char *)(((((uintptr_t)m)+PSYNC_AES256_BLOCK_SIZE-1)/PSYNC_AES256_BLOCK_SIZE)*PSYNC_AES256_BLOCK_SIZE);
|
|
||||||
a[sizeof(AES_KEY)]=a-m;
|
|
||||||
return (AES_KEY *)a;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void psync_ssl_free_aligned_aes_key(AES_KEY *aes){
|
|
||||||
unsigned char *a;
|
|
||||||
a=(unsigned char *)aes;
|
|
||||||
a-=a[sizeof(AES_KEY)];
|
|
||||||
psync_ssl_memclean(aes, sizeof(AES_KEY));
|
|
||||||
psync_locked_free(a);
|
|
||||||
}
|
|
||||||
|
|
||||||
psync_aes256_encoder psync_ssl_aes256_create_encoder(psync_symmetric_key_t key){
|
|
||||||
AES_KEY *aes;
|
|
||||||
assert(key->keylen>=PSYNC_AES256_KEY_SIZE);
|
|
||||||
aes=psync_ssl_get_aligned_aes_key();
|
|
||||||
AES_set_encrypt_key(key->key, 256, aes);
|
|
||||||
return aes;
|
|
||||||
}
|
|
||||||
|
|
||||||
void psync_ssl_aes256_free_encoder(psync_aes256_encoder aes){
|
|
||||||
psync_ssl_free_aligned_aes_key(aes);
|
|
||||||
}
|
|
||||||
|
|
||||||
psync_aes256_encoder psync_ssl_aes256_create_decoder(psync_symmetric_key_t key){
|
|
||||||
AES_KEY *aes;
|
|
||||||
assert(key->keylen>=PSYNC_AES256_KEY_SIZE);
|
|
||||||
aes=psync_ssl_get_aligned_aes_key();
|
|
||||||
AES_set_decrypt_key(key->key, 256, aes);
|
|
||||||
return aes;
|
|
||||||
}
|
|
||||||
|
|
||||||
void psync_ssl_aes256_free_decoder(psync_aes256_encoder aes){
|
|
||||||
psync_ssl_free_aligned_aes_key(aes);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(PSYNC_AES_HW_GCC)
|
|
||||||
|
|
||||||
#define SSE2FUNC __attribute__((__target__("sse2")))
|
|
||||||
|
|
||||||
#define AESDEC ".byte 0x66,0x0F,0x38,0xDE,"
|
|
||||||
#define AESDECLAST ".byte 0x66,0x0F,0x38,0xDF,"
|
|
||||||
#define AESENC ".byte 0x66,0x0F,0x38,0xDC,"
|
|
||||||
#define AESENCLAST ".byte 0x66,0x0F,0x38,0xDD,"
|
|
||||||
|
|
||||||
#define xmm0_xmm1 "0xC8"
|
|
||||||
#define xmm0_xmm2 "0xD0"
|
|
||||||
#define xmm0_xmm3 "0xD8"
|
|
||||||
#define xmm0_xmm4 "0xE0"
|
|
||||||
#define xmm0_xmm5 "0xE8"
|
|
||||||
#define xmm1_xmm0 "0xC1"
|
|
||||||
#define xmm1_xmm2 "0xD1"
|
|
||||||
#define xmm1_xmm3 "0xD9"
|
|
||||||
#define xmm1_xmm4 "0xE1"
|
|
||||||
#define xmm1_xmm5 "0xE9"
|
|
||||||
|
|
||||||
SSE2FUNC void psync_aes256_encode_block_hw(psync_aes256_encoder enc, const unsigned char *src, unsigned char *dst){
|
|
||||||
asm("movdqa (%0), %%xmm0\n"
|
|
||||||
"lea 16(%0), %0\n"
|
|
||||||
"movdqa (%1), %%xmm1\n"
|
|
||||||
"dec %3\n"
|
|
||||||
"pxor %%xmm0, %%xmm1\n"
|
|
||||||
"movdqa (%0), %%xmm0\n"
|
|
||||||
"1:\n"
|
|
||||||
"lea 16(%0), %0\n"
|
|
||||||
"dec %3\n"
|
|
||||||
AESENC xmm0_xmm1 "\n"
|
|
||||||
"movdqa (%0), %%xmm0\n"
|
|
||||||
"jnz 1b\n"
|
|
||||||
AESENCLAST xmm0_xmm1 "\n"
|
|
||||||
"movdqa %%xmm1, (%2)\n"
|
|
||||||
:
|
|
||||||
: "r" (enc->rd_key), "r" (src), "r" (dst), "r" (enc->rounds)
|
|
||||||
: "memory", "cc", "xmm0", "xmm1"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
SSE2FUNC void psync_aes256_decode_block_hw(psync_aes256_decoder enc, const unsigned char *src, unsigned char *dst){
|
|
||||||
asm("movdqa (%0), %%xmm0\n"
|
|
||||||
"lea 16(%0), %0\n"
|
|
||||||
"movdqa (%1), %%xmm1\n"
|
|
||||||
"dec %3\n"
|
|
||||||
"pxor %%xmm0, %%xmm1\n"
|
|
||||||
"movdqa (%0), %%xmm0\n"
|
|
||||||
"1:\n"
|
|
||||||
"lea 16(%0), %0\n"
|
|
||||||
"dec %3\n"
|
|
||||||
AESDEC xmm0_xmm1 "\n"
|
|
||||||
"movdqa (%0), %%xmm0\n"
|
|
||||||
"jnz 1b\n"
|
|
||||||
AESDECLAST xmm0_xmm1 "\n"
|
|
||||||
"movdqa %%xmm1, (%2)\n"
|
|
||||||
:
|
|
||||||
: "r" (enc->rd_key), "r" (src), "r" (dst), "r" (enc->rounds)
|
|
||||||
: "memory", "cc", "xmm0", "xmm1"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
SSE2FUNC void psync_aes256_encode_2blocks_consec_hw(psync_aes256_encoder enc, const unsigned char *src, unsigned char *dst){
|
|
||||||
asm("movdqa (%0), %%xmm0\n"
|
|
||||||
"movdqa (%1), %%xmm1\n"
|
|
||||||
"dec %3\n"
|
|
||||||
"movdqa 16(%1), %%xmm2\n"
|
|
||||||
"lea 16(%0), %0\n"
|
|
||||||
"xorps %%xmm0, %%xmm1\n"
|
|
||||||
"pxor %%xmm0, %%xmm2\n"
|
|
||||||
"movdqa (%0), %%xmm0\n"
|
|
||||||
"1:\n"
|
|
||||||
"lea 16(%0), %0\n"
|
|
||||||
AESENC xmm0_xmm1 "\n"
|
|
||||||
"dec %3\n"
|
|
||||||
AESENC xmm0_xmm2 "\n"
|
|
||||||
"movdqa (%0), %%xmm0\n"
|
|
||||||
"jnz 1b\n"
|
|
||||||
AESENCLAST xmm0_xmm1 "\n"
|
|
||||||
AESENCLAST xmm0_xmm2 "\n"
|
|
||||||
"movdqa %%xmm1, (%2)\n"
|
|
||||||
"movdqa %%xmm2, 16(%2)\n"
|
|
||||||
:
|
|
||||||
: "r" (enc->rd_key), "r" (src), "r" (dst), "r" (enc->rounds)
|
|
||||||
: "memory", "cc", "xmm0", "xmm1", "xmm2"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
SSE2FUNC void psync_aes256_decode_2blocks_consec_hw(psync_aes256_decoder enc, const unsigned char *src, unsigned char *dst){
|
|
||||||
asm("movdqa (%0), %%xmm0\n"
|
|
||||||
"movdqa (%1), %%xmm1\n"
|
|
||||||
"dec %3\n"
|
|
||||||
"movdqa 16(%1), %%xmm2\n"
|
|
||||||
"lea 16(%0), %0\n"
|
|
||||||
"xorps %%xmm0, %%xmm1\n"
|
|
||||||
"pxor %%xmm0, %%xmm2\n"
|
|
||||||
"movdqa (%0), %%xmm0\n"
|
|
||||||
"1:\n"
|
|
||||||
"lea 16(%0), %0\n"
|
|
||||||
AESDEC xmm0_xmm1 "\n"
|
|
||||||
"dec %3\n"
|
|
||||||
AESDEC xmm0_xmm2 "\n"
|
|
||||||
"movdqa (%0), %%xmm0\n"
|
|
||||||
"jnz 1b\n"
|
|
||||||
AESDECLAST xmm0_xmm1 "\n"
|
|
||||||
AESDECLAST xmm0_xmm2 "\n"
|
|
||||||
"movdqa %%xmm1, (%2)\n"
|
|
||||||
"movdqa %%xmm2, 16(%2)\n"
|
|
||||||
:
|
|
||||||
: "r" (enc->rd_key), "r" (src), "r" (dst), "r" (enc->rounds)
|
|
||||||
: "memory", "cc", "xmm0", "xmm1", "xmm2"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
SSE2FUNC void psync_aes256_decode_4blocks_consec_xor_hw(psync_aes256_decoder enc, const unsigned char *src, unsigned char *dst, unsigned char *bxor){
|
|
||||||
asm("movdqa (%0), %%xmm0\n"
|
|
||||||
"shr %4\n"
|
|
||||||
"movdqa (%1), %%xmm2\n"
|
|
||||||
"dec %4\n"
|
|
||||||
"movdqa 16(%1), %%xmm3\n"
|
|
||||||
"xorps %%xmm0, %%xmm2\n"
|
|
||||||
"movdqa 32(%1), %%xmm4\n"
|
|
||||||
"xorps %%xmm0, %%xmm3\n"
|
|
||||||
"movdqa 48(%1), %%xmm5\n"
|
|
||||||
"pxor %%xmm0, %%xmm4\n"
|
|
||||||
"movdqa 16(%0), %%xmm1\n"
|
|
||||||
"pxor %%xmm0, %%xmm5\n"
|
|
||||||
"1:\n"
|
|
||||||
"lea 32(%0), %0\n"
|
|
||||||
"dec %4\n"
|
|
||||||
AESDEC xmm1_xmm2 "\n"
|
|
||||||
"movdqa (%0), %%xmm0\n"
|
|
||||||
AESDEC xmm1_xmm3 "\n"
|
|
||||||
AESDEC xmm1_xmm4 "\n"
|
|
||||||
AESDEC xmm1_xmm5 "\n"
|
|
||||||
AESDEC xmm0_xmm2 "\n"
|
|
||||||
"movdqa 16(%0), %%xmm1\n"
|
|
||||||
AESDEC xmm0_xmm3 "\n"
|
|
||||||
AESDEC xmm0_xmm4 "\n"
|
|
||||||
AESDEC xmm0_xmm5 "\n"
|
|
||||||
"jnz 1b\n"
|
|
||||||
AESDEC xmm1_xmm2 "\n"
|
|
||||||
"movdqa 32(%0), %%xmm0\n"
|
|
||||||
AESDEC xmm1_xmm3 "\n"
|
|
||||||
AESDEC xmm1_xmm4 "\n"
|
|
||||||
AESDEC xmm1_xmm5 "\n"
|
|
||||||
AESDECLAST xmm0_xmm2 "\n"
|
|
||||||
AESDECLAST xmm0_xmm3 "\n"
|
|
||||||
AESDECLAST xmm0_xmm4 "\n"
|
|
||||||
"pxor (%3), %%xmm2\n"
|
|
||||||
AESDECLAST xmm0_xmm5 "\n"
|
|
||||||
"pxor 16(%3), %%xmm3\n"
|
|
||||||
"movdqa %%xmm2, (%2)\n"
|
|
||||||
"pxor 32(%3), %%xmm4\n"
|
|
||||||
"movdqa %%xmm3, 16(%2)\n"
|
|
||||||
"pxor 48(%3), %%xmm5\n"
|
|
||||||
"movdqa %%xmm4, 32(%2)\n"
|
|
||||||
"movdqa %%xmm5, 48(%2)\n"
|
|
||||||
:
|
|
||||||
: "r" (enc->rd_key), "r" (src), "r" (dst), "r" (bxor), "r" (enc->rounds)
|
|
||||||
: "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#elif defined(PSYNC_AES_HW_MSC)
|
|
||||||
|
|
||||||
void psync_aes256_encode_block_hw(psync_aes256_encoder enc, const unsigned char *src, unsigned char *dst){
|
|
||||||
__m128i r0, r1;
|
|
||||||
unsigned char *key;
|
|
||||||
unsigned cnt;
|
|
||||||
key=(unsigned char *)enc->rd_key;
|
|
||||||
r0=_mm_load_si128((__m128i *)key);
|
|
||||||
r1=_mm_load_si128((__m128i *)src);
|
|
||||||
cnt=enc->rounds-1;
|
|
||||||
key+=16;
|
|
||||||
r1=_mm_xor_si128(r0, r1);
|
|
||||||
r0=_mm_load_si128((__m128i *)key);
|
|
||||||
do{
|
|
||||||
key+=16;
|
|
||||||
r1=_mm_aesenc_si128(r1, r0);
|
|
||||||
r0=_mm_load_si128((__m128i *)key);
|
|
||||||
} while (--cnt);
|
|
||||||
r1=_mm_aesenclast_si128(r1, r0);
|
|
||||||
_mm_store_si128((__m128i *)dst, r1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void psync_aes256_decode_block_hw(psync_aes256_encoder enc, const unsigned char *src, unsigned char *dst){
|
|
||||||
__m128i r0, r1;
|
|
||||||
unsigned char *key;
|
|
||||||
unsigned cnt;
|
|
||||||
key=(unsigned char *)enc->rd_key;
|
|
||||||
r0=_mm_load_si128((__m128i *)key);
|
|
||||||
r1=_mm_load_si128((__m128i *)src);
|
|
||||||
cnt=enc->rounds-1;
|
|
||||||
key+=16;
|
|
||||||
r1=_mm_xor_si128(r0, r1);
|
|
||||||
r0=_mm_load_si128((__m128i *)key);
|
|
||||||
do{
|
|
||||||
key+=16;
|
|
||||||
r1=_mm_aesdec_si128(r1, r0);
|
|
||||||
r0=_mm_load_si128((__m128i *)key);
|
|
||||||
} while (--cnt);
|
|
||||||
r1=_mm_aesdeclast_si128(r1, r0);
|
|
||||||
_mm_store_si128((__m128i *)dst, r1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void psync_aes256_encode_2blocks_consec_hw(psync_aes256_encoder enc, const unsigned char *src, unsigned char *dst){
|
|
||||||
__m128i r0, r1, r2;
|
|
||||||
unsigned char *key;
|
|
||||||
unsigned cnt;
|
|
||||||
key=(unsigned char *)enc->rd_key;
|
|
||||||
r0=_mm_load_si128((__m128i *)key);
|
|
||||||
r1=_mm_load_si128((__m128i *)src);
|
|
||||||
r2=_mm_load_si128((__m128i *)(src+16));
|
|
||||||
cnt=enc->rounds-1;
|
|
||||||
key+=16;
|
|
||||||
r1=_mm_xor_si128(r0, r1);
|
|
||||||
r2=_mm_xor_si128(r0, r2);
|
|
||||||
r0=_mm_load_si128((__m128i *)key);
|
|
||||||
do{
|
|
||||||
key+=16;
|
|
||||||
r1=_mm_aesenc_si128(r1, r0);
|
|
||||||
r2=_mm_aesenc_si128(r2, r0);
|
|
||||||
r0=_mm_load_si128((__m128i *)key);
|
|
||||||
} while (--cnt);
|
|
||||||
r1=_mm_aesenclast_si128(r1, r0);
|
|
||||||
r2=_mm_aesenclast_si128(r2, r0);
|
|
||||||
_mm_store_si128((__m128i *)dst, r1);
|
|
||||||
_mm_store_si128((__m128i *)(dst+16), r2);
|
|
||||||
}
|
|
||||||
|
|
||||||
void psync_aes256_decode_2blocks_consec_hw(psync_aes256_decoder enc, const unsigned char *src, unsigned char *dst){
|
|
||||||
__m128i r0, r1, r2;
|
|
||||||
unsigned char *key;
|
|
||||||
unsigned cnt;
|
|
||||||
key=(unsigned char *)enc->rd_key;
|
|
||||||
r0=_mm_load_si128((__m128i *)key);
|
|
||||||
r1=_mm_load_si128((__m128i *)src);
|
|
||||||
r2=_mm_load_si128((__m128i *)(src+16));
|
|
||||||
cnt=enc->rounds-1;
|
|
||||||
key+=16;
|
|
||||||
r1=_mm_xor_si128(r0, r1);
|
|
||||||
r2=_mm_xor_si128(r0, r2);
|
|
||||||
r0=_mm_load_si128((__m128i *)key);
|
|
||||||
do{
|
|
||||||
key+=16;
|
|
||||||
r1=_mm_aesdec_si128(r1, r0);
|
|
||||||
r2=_mm_aesdec_si128(r2, r0);
|
|
||||||
r0=_mm_load_si128((__m128i *)key);
|
|
||||||
} while (--cnt);
|
|
||||||
r1=_mm_aesdeclast_si128(r1, r0);
|
|
||||||
r2=_mm_aesdeclast_si128(r2, r0);
|
|
||||||
_mm_store_si128((__m128i *)dst, r1);
|
|
||||||
_mm_store_si128((__m128i *)(dst+16), r2);
|
|
||||||
}
|
|
||||||
|
|
||||||
void psync_aes256_decode_4blocks_consec_xor_hw(psync_aes256_decoder enc, const unsigned char *src, unsigned char *dst, unsigned char *bxor){
|
|
||||||
__m128i r0, r1, r2, r3, r4;
|
|
||||||
unsigned char *key;
|
|
||||||
unsigned cnt;
|
|
||||||
key=(unsigned char *)enc->rd_key;
|
|
||||||
r0=_mm_load_si128((__m128i *)key);
|
|
||||||
r1=_mm_load_si128((__m128i *)src);
|
|
||||||
r2=_mm_load_si128((__m128i *)(src+16));
|
|
||||||
r3=_mm_load_si128((__m128i *)(src+32));
|
|
||||||
r4=_mm_load_si128((__m128i *)(src+48));
|
|
||||||
cnt=enc->rounds-1;
|
|
||||||
key+=16;
|
|
||||||
r1=_mm_xor_si128(r0, r1);
|
|
||||||
r2=_mm_xor_si128(r0, r2);
|
|
||||||
r3=_mm_xor_si128(r0, r3);
|
|
||||||
r4=_mm_xor_si128(r0, r4);
|
|
||||||
r0=_mm_load_si128((__m128i *)key);
|
|
||||||
do{
|
|
||||||
key+=16;
|
|
||||||
r1=_mm_aesdec_si128(r1, r0);
|
|
||||||
r2=_mm_aesdec_si128(r2, r0);
|
|
||||||
r3=_mm_aesdec_si128(r3, r0);
|
|
||||||
r4=_mm_aesdec_si128(r4, r0);
|
|
||||||
r0=_mm_load_si128((__m128i *)key);
|
|
||||||
} while (--cnt);
|
|
||||||
r1=_mm_aesdeclast_si128(r1, r0);
|
|
||||||
r2=_mm_aesdeclast_si128(r2, r0);
|
|
||||||
r3=_mm_aesdeclast_si128(r3, r0);
|
|
||||||
r4=_mm_aesdeclast_si128(r4, r0);
|
|
||||||
r0=_mm_load_si128((__m128i *)bxor);
|
|
||||||
r1=_mm_xor_si128(r0, r1);
|
|
||||||
r0=_mm_load_si128((__m128i *)(bxor+16));
|
|
||||||
_mm_store_si128((__m128i *)dst, r1);
|
|
||||||
r2=_mm_xor_si128(r0, r2);
|
|
||||||
r0=_mm_load_si128((__m128i *)(bxor+32));
|
|
||||||
_mm_store_si128((__m128i *)(dst+16), r2);
|
|
||||||
r3=_mm_xor_si128(r0, r3);
|
|
||||||
r0=_mm_load_si128((__m128i *)(bxor+48));
|
|
||||||
_mm_store_si128((__m128i *)(dst+32), r3);
|
|
||||||
r4=_mm_xor_si128(r0, r4);
|
|
||||||
_mm_store_si128((__m128i *)(dst+48), r4);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(PSYNC_AES_HW)
|
|
||||||
|
|
||||||
void psync_aes256_decode_4blocks_consec_xor_sw(psync_aes256_decoder enc, const unsigned char *src, unsigned char *dst, unsigned char *bxor){
|
|
||||||
unsigned long i;
|
|
||||||
AES_decrypt(src, dst, enc);
|
|
||||||
AES_decrypt(src+PSYNC_AES256_BLOCK_SIZE, dst+PSYNC_AES256_BLOCK_SIZE, enc);
|
|
||||||
AES_decrypt(src+PSYNC_AES256_BLOCK_SIZE*2, dst+PSYNC_AES256_BLOCK_SIZE*2, enc);
|
|
||||||
AES_decrypt(src+PSYNC_AES256_BLOCK_SIZE*3, dst+PSYNC_AES256_BLOCK_SIZE*3, enc);
|
|
||||||
for (i=0; i<PSYNC_AES256_BLOCK_SIZE*4/sizeof(unsigned long); i++)
|
|
||||||
((unsigned long *)dst)[i]^=((unsigned long *)bxor)[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,538 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright (c) 2013-2014 Anton Titov.
|
|
||||||
|
|
||||||
Copyright (c) 2013-2014 pCloud Ltd. All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions
|
|
||||||
are met: Redistributions of source code must retain the above
|
|
||||||
copyright notice, this list of conditions and the following
|
|
||||||
disclaimer. Redistributions in binary form must reproduce the
|
|
||||||
above copyright notice, this list of conditions and the following
|
|
||||||
disclaimer in the documentation and/or other materials provided
|
|
||||||
with the distribution. Neither the name of pCloud Ltd nor the
|
|
||||||
names of its contributors may be used to endorse or promote
|
|
||||||
products derived from this software without specific prior written
|
|
||||||
permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
||||||
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL pCloud
|
|
||||||
Ltd BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
||||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
|
||||||
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
|
||||||
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
|
||||||
DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "pssl.h"
|
|
||||||
#include "psynclib.h"
|
|
||||||
#include "plibs.h"
|
|
||||||
#include "pcompat.h"
|
|
||||||
#include "psettings.h"
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <CommonCrypto/CommonHMAC.h>
|
|
||||||
#include <Security/SecureTransport.h>
|
|
||||||
#include <Security/SecImportExport.h>
|
|
||||||
#include <Security/Security.h>
|
|
||||||
#include <Security/SecKey.h>
|
|
||||||
|
|
||||||
#define kSecPaddingOAEP 2
|
|
||||||
|
|
||||||
OSStatus SecKeyEncrypt(
|
|
||||||
SecKeyRef key,
|
|
||||||
SecPadding padding,
|
|
||||||
const uint8_t *plainText,
|
|
||||||
size_t plainTextLen,
|
|
||||||
uint8_t *cipherText,
|
|
||||||
size_t *cipherTextLen);
|
|
||||||
|
|
||||||
OSStatus SecKeyDecrypt(
|
|
||||||
SecKeyRef key,
|
|
||||||
SecPadding padding,
|
|
||||||
const uint8_t *cipherText,
|
|
||||||
size_t cipherTextLen,
|
|
||||||
uint8_t *plainText,
|
|
||||||
size_t *plainTextLen);
|
|
||||||
|
|
||||||
PSYNC_THREAD int psync_ssl_errno;
|
|
||||||
|
|
||||||
int psync_ssl_init(){
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void psync_ssl_memclean(void *ptr, size_t len){
|
|
||||||
volatile unsigned char *c=(volatile unsigned char *)ptr;
|
|
||||||
while (len--)
|
|
||||||
*c++=0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static OSStatus psync_myread(SSLConnectionRef conn, void *data, size_t *len){
|
|
||||||
psync_socket_t sock=(psync_socket_t)conn;
|
|
||||||
size_t llen=*len;
|
|
||||||
ssize_t rd=read(sock, data, llen);
|
|
||||||
if (likely(rd>0)){
|
|
||||||
*len=rd;
|
|
||||||
if (rd==llen)
|
|
||||||
return noErr;
|
|
||||||
psync_ssl_errno=PSYNC_SSL_ERR_WANT_READ;
|
|
||||||
return errSSLWouldBlock;
|
|
||||||
}
|
|
||||||
else if (rd==0){
|
|
||||||
*len=0;
|
|
||||||
return errSSLClosedNoNotify;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
*len=0;
|
|
||||||
if (errno==EAGAIN || errno==EINTR){
|
|
||||||
psync_ssl_errno=PSYNC_SSL_ERR_WANT_READ;
|
|
||||||
return errSSLWouldBlock;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return errSSLClosedAbort;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static OSStatus psync_mywrite(SSLConnectionRef conn, const void *data, size_t *len){
|
|
||||||
psync_socket_t sock=(psync_socket_t)conn;
|
|
||||||
size_t llen=*len;
|
|
||||||
ssize_t rd=write(sock, data, llen);
|
|
||||||
if (likely(rd>=0)){
|
|
||||||
*len=rd;
|
|
||||||
if (rd==llen)
|
|
||||||
return noErr;
|
|
||||||
psync_ssl_errno=PSYNC_SSL_ERR_WANT_WRITE;
|
|
||||||
return errSSLWouldBlock;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
*len=0;
|
|
||||||
if (errno==EAGAIN || errno==EINTR){
|
|
||||||
psync_ssl_errno=PSYNC_SSL_ERR_WANT_WRITE;
|
|
||||||
return errSSLWouldBlock;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return errSSLClosedAbort;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int psync_ssl_connect(psync_socket_t sock, void **sslconn, const char *hostname){
|
|
||||||
SSLContextRef ref;
|
|
||||||
OSStatus st;
|
|
||||||
ref=SSLCreateContext(kCFAllocatorDefault, kSSLClientSide, kSSLStreamType);
|
|
||||||
if (unlikely_log(!ref))
|
|
||||||
goto err1;
|
|
||||||
if (unlikely_log(SSLSetIOFuncs(ref, psync_myread, psync_mywrite)!=noErr))
|
|
||||||
goto err2;
|
|
||||||
if (unlikely_log(SSLSetConnection(ref, (SSLConnectionRef)(uintptr_t)sock)!=noErr))
|
|
||||||
goto err2;
|
|
||||||
if (hostname && unlikely_log(SSLSetPeerDomainName(ref, hostname, strlen(hostname))!=noErr))
|
|
||||||
goto err2;
|
|
||||||
st=SSLHandshake(ref);
|
|
||||||
if (st==noErr){
|
|
||||||
*sslconn=ref;
|
|
||||||
return PSYNC_SSL_SUCCESS;
|
|
||||||
}
|
|
||||||
else if (st==errSSLWouldBlock){
|
|
||||||
*sslconn=ref;
|
|
||||||
return PSYNC_SSL_NEED_FINISH;
|
|
||||||
}
|
|
||||||
debug(D_WARNING, "connection failed with status %d", (int)st);
|
|
||||||
err2:
|
|
||||||
CFRelease(ref);
|
|
||||||
err1:
|
|
||||||
psync_ssl_errno=PSYNC_SSL_ERR_UNKNOWN;
|
|
||||||
return PSYNC_SSL_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int psync_ssl_connect_finish(void *sslconn, const char *hostname){
|
|
||||||
SSLContextRef ref;
|
|
||||||
OSStatus st;
|
|
||||||
ref=(SSLContextRef)sslconn;
|
|
||||||
st=SSLHandshake(ref);
|
|
||||||
if (st==noErr)
|
|
||||||
return PSYNC_SSL_SUCCESS;
|
|
||||||
else if (st==errSSLWouldBlock)
|
|
||||||
return PSYNC_SSL_NEED_FINISH;
|
|
||||||
CFRelease(ref);
|
|
||||||
debug(D_WARNING, "connection failed with status %d", (int)st);
|
|
||||||
psync_ssl_errno=PSYNC_SSL_ERR_UNKNOWN;
|
|
||||||
return PSYNC_SSL_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int psync_ssl_shutdown(void *sslconn){
|
|
||||||
SSLContextRef ref;
|
|
||||||
OSStatus st;
|
|
||||||
ref=(SSLContextRef)sslconn;
|
|
||||||
st=SSLClose(ref);
|
|
||||||
if (st==errSSLWouldBlock)
|
|
||||||
return PSYNC_SSL_NEED_FINISH;
|
|
||||||
CFRelease(ref);
|
|
||||||
if (st==noErr)
|
|
||||||
return PSYNC_SSL_SUCCESS;
|
|
||||||
psync_ssl_errno=PSYNC_SSL_ERR_UNKNOWN;
|
|
||||||
return PSYNC_SSL_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void psync_ssl_free(void *sslconn){
|
|
||||||
CFRelease((SSLContextRef)sslconn);
|
|
||||||
}
|
|
||||||
|
|
||||||
int psync_ssl_pendingdata(void *sslconn){
|
|
||||||
size_t p;
|
|
||||||
if (SSLGetBufferedReadSize((SSLContextRef)sslconn, &p)==noErr)
|
|
||||||
return p;
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int psync_ssl_read(void *sslconn, void *buf, int num){
|
|
||||||
size_t ret;
|
|
||||||
OSStatus st;
|
|
||||||
psync_ssl_errno=PSYNC_SSL_ERR_UNKNOWN;
|
|
||||||
st=SSLRead((SSLContextRef)sslconn, buf, num, &ret);
|
|
||||||
if (st!=noErr){
|
|
||||||
if (st==errSSLWouldBlock && ret)
|
|
||||||
return ret;
|
|
||||||
else if (st==errSSLClosedGraceful)
|
|
||||||
return 0;
|
|
||||||
else{
|
|
||||||
if (st!=errSSLWouldBlock)
|
|
||||||
debug(D_WARNING, "read failed with error %d", (int)st);
|
|
||||||
return PSYNC_SSL_FAIL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int psync_ssl_write(void *sslconn, const void *buf, int num){
|
|
||||||
size_t ret;
|
|
||||||
OSStatus st;
|
|
||||||
psync_ssl_errno=PSYNC_SSL_ERR_UNKNOWN;
|
|
||||||
st=SSLWrite((SSLContextRef)sslconn, buf, num, &ret);
|
|
||||||
if (st!=noErr){
|
|
||||||
if (st==errSSLWouldBlock && ret)
|
|
||||||
return ret;
|
|
||||||
else{
|
|
||||||
if (st!=errSSLWouldBlock)
|
|
||||||
debug(D_WARNING, "write failed with error %d", (int)st);
|
|
||||||
return PSYNC_SSL_FAIL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void psync_ssl_rand_strong(unsigned char *buf, int num){
|
|
||||||
ssize_t ret;
|
|
||||||
int fd;
|
|
||||||
fd=open("/dev/random", O_RDONLY);
|
|
||||||
if (unlikely_log(fd==-1))
|
|
||||||
goto err;
|
|
||||||
while (num){
|
|
||||||
ret=read(fd, buf, num);
|
|
||||||
if (unlikely_log(ret<=0))
|
|
||||||
goto err;
|
|
||||||
num-=ret;
|
|
||||||
buf+=ret;
|
|
||||||
}
|
|
||||||
close(fd);
|
|
||||||
return;
|
|
||||||
err:
|
|
||||||
debug(D_CRITICAL, "could not open /dev/random");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void psync_ssl_rand_weak(unsigned char *buf, int num){
|
|
||||||
sqlite3_randomness(num, buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
psync_rsa_t psync_ssl_gen_rsa(int bits){
|
|
||||||
psync_rsa_t ret;
|
|
||||||
SecKeyRef public_key, private_key;
|
|
||||||
CFDictionaryRef dict;
|
|
||||||
CFTypeRef keys[2], values[2];
|
|
||||||
OSStatus st;
|
|
||||||
keys[0]=kSecAttrKeyType;
|
|
||||||
values[0]=kSecAttrKeyTypeRSA;
|
|
||||||
keys[1]=kSecAttrKeySizeInBits;
|
|
||||||
values[1]=CFNumberCreate(NULL, kCFNumberIntType, &bits);
|
|
||||||
dict=CFDictionaryCreate(NULL, keys, values, ARRAY_SIZE(keys), NULL, NULL);
|
|
||||||
st=SecKeyGeneratePair(dict, &public_key, &private_key);
|
|
||||||
CFRelease(dict);
|
|
||||||
CFRelease(values[1]);
|
|
||||||
if (unlikely(st!=errSecSuccess)){
|
|
||||||
debug(D_ERROR, "RSA key generation failed with error %d", (int)st);
|
|
||||||
return PSYNC_INVALID_RSA;
|
|
||||||
}
|
|
||||||
ret=psync_new(psync_rsa_struct_t);
|
|
||||||
ret->public_key=public_key;
|
|
||||||
ret->private_key=private_key;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void psync_ssl_free_rsa(psync_rsa_t rsa){
|
|
||||||
CFRelease(rsa->public_key);
|
|
||||||
CFRelease(rsa->private_key);
|
|
||||||
psync_free(rsa);
|
|
||||||
}
|
|
||||||
|
|
||||||
psync_rsa_publickey_t psync_ssl_rsa_get_public(psync_rsa_t rsa){
|
|
||||||
CFRetain(rsa->public_key);
|
|
||||||
return rsa->public_key;
|
|
||||||
}
|
|
||||||
|
|
||||||
void psync_ssl_rsa_free_public(psync_rsa_publickey_t key){
|
|
||||||
CFRelease(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
psync_rsa_privatekey_t psync_ssl_rsa_get_private(psync_rsa_t rsa){
|
|
||||||
CFRetain(rsa->private_key);
|
|
||||||
return rsa->private_key;
|
|
||||||
}
|
|
||||||
|
|
||||||
void psync_ssl_rsa_free_private(psync_rsa_privatekey_t key){
|
|
||||||
CFRelease(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
psync_binary_rsa_key_t psync_ssl_rsa_public_to_binary(psync_rsa_publickey_t rsa){
|
|
||||||
psync_binary_rsa_key_t ret;
|
|
||||||
CFDictionaryRef dict;
|
|
||||||
CFTypeRef keys[4], values[4], arrval[1];
|
|
||||||
CFArrayRef arr;
|
|
||||||
OSStatus st;
|
|
||||||
CFDataRef data;
|
|
||||||
CFIndex len;
|
|
||||||
arrval[0]=rsa;
|
|
||||||
arr=CFArrayCreate(NULL, arrval, 1, NULL);
|
|
||||||
keys[0]=kSecAttrKeyType;
|
|
||||||
values[0]=kSecAttrKeyTypeRSA;
|
|
||||||
keys[1]=kSecReturnData;
|
|
||||||
values[1]=kCFBooleanTrue;
|
|
||||||
keys[2]=kSecClass;
|
|
||||||
values[2]=kSecClassKey;
|
|
||||||
keys[3]=kSecMatchItemList;
|
|
||||||
values[3]=arr;
|
|
||||||
dict=CFDictionaryCreate(NULL, keys, values, ARRAY_SIZE(keys), NULL, NULL);
|
|
||||||
data=NULL;
|
|
||||||
st=SecItemCopyMatching(dict, (CFTypeRef *)&data);
|
|
||||||
CFRelease(dict);
|
|
||||||
CFRelease(arr);
|
|
||||||
if (unlikely_log(st!=errSecSuccess))
|
|
||||||
return PSYNC_INVALID_BIN_RSA;
|
|
||||||
len=CFDataGetLength(data);
|
|
||||||
ret=psync_malloc(offsetof(psync_encrypted_data_struct_t, data)+len);
|
|
||||||
ret->datalen=len;
|
|
||||||
memcpy(ret->data, CFDataGetBytePtr(data), len);
|
|
||||||
CFRelease(data);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
psync_binary_rsa_key_t psync_ssl_rsa_private_to_binary(psync_rsa_privatekey_t rsa){
|
|
||||||
psync_binary_rsa_key_t ret;
|
|
||||||
CFDictionaryRef dict;
|
|
||||||
CFTypeRef keys[4], values[4], arrval[1];
|
|
||||||
CFArrayRef arr;
|
|
||||||
OSStatus st;
|
|
||||||
CFDataRef data;
|
|
||||||
CFIndex len;
|
|
||||||
arrval[0]=rsa;
|
|
||||||
arr=CFArrayCreate(NULL, arrval, 1, NULL);
|
|
||||||
keys[0]=kSecAttrKeyType;
|
|
||||||
values[0]=kSecAttrKeyTypeRSA;
|
|
||||||
keys[1]=kSecReturnData;
|
|
||||||
values[1]=kCFBooleanTrue;
|
|
||||||
keys[2]=kSecClass;
|
|
||||||
values[2]=kSecAttrKeyClassPrivate;
|
|
||||||
keys[3]=kSecMatchItemList;
|
|
||||||
values[3]=arr;
|
|
||||||
dict=CFDictionaryCreate(NULL, keys, values, ARRAY_SIZE(keys), NULL, NULL);
|
|
||||||
data=NULL;
|
|
||||||
st=SecItemCopyMatching(dict, (CFTypeRef *)&data);
|
|
||||||
CFRelease(dict);
|
|
||||||
CFRelease(arr);
|
|
||||||
if (unlikely_log(st!=errSecSuccess))
|
|
||||||
return PSYNC_INVALID_BIN_RSA;
|
|
||||||
len=CFDataGetLength(data);
|
|
||||||
ret=psync_malloc(offsetof(psync_encrypted_data_struct_t, data)+len);
|
|
||||||
ret->datalen=len;
|
|
||||||
memcpy(ret->data, CFDataGetBytePtr(data), len);
|
|
||||||
CFRelease(data);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
psync_rsa_publickey_t psync_ssl_rsa_binary_to_public(psync_binary_rsa_key_t bin){
|
|
||||||
/* on iOS SecKeyCreateRSAPublicKey can be used */
|
|
||||||
SecKeyRef ret;
|
|
||||||
SecExternalFormat form;
|
|
||||||
SecExternalItemType type;
|
|
||||||
CFDataRef data;
|
|
||||||
CFArrayRef out;
|
|
||||||
OSStatus st;
|
|
||||||
|
|
||||||
form=kSecFormatUnknown;
|
|
||||||
type=kSecItemTypePublicKey;
|
|
||||||
data=CFDataCreate(NULL, bin->data, bin->datalen);
|
|
||||||
st=SecItemImport(data, NULL, &form, &type, 0, NULL, NULL, &out);
|
|
||||||
CFRelease(data);
|
|
||||||
if (unlikely_log(st!=errSecSuccess))
|
|
||||||
PSYNC_INVALID_RSA;
|
|
||||||
ret=(SecKeyRef)CFArrayGetValueAtIndex(out, 0);
|
|
||||||
if (unlikely_log(ret==NULL)){
|
|
||||||
CFRelease(out);
|
|
||||||
return PSYNC_INVALID_RSA;
|
|
||||||
}
|
|
||||||
CFRetain(ret);
|
|
||||||
CFRelease(out);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
psync_rsa_privatekey_t psync_ssl_rsa_binary_to_private(psync_binary_rsa_key_t bin){
|
|
||||||
SecKeyRef ret;
|
|
||||||
SecExternalFormat form;
|
|
||||||
SecExternalItemType type;
|
|
||||||
CFDataRef data;
|
|
||||||
CFArrayRef out;
|
|
||||||
OSStatus st;
|
|
||||||
|
|
||||||
form=kSecFormatUnknown;
|
|
||||||
type=kSecItemTypePrivateKey;
|
|
||||||
data=CFDataCreate(NULL, bin->data, bin->datalen);
|
|
||||||
st=SecItemImport(data, NULL, &form, &type, 0, NULL, NULL, &out);
|
|
||||||
CFRelease(data);
|
|
||||||
if (unlikely_log(st!=errSecSuccess))
|
|
||||||
PSYNC_INVALID_RSA;
|
|
||||||
ret=(SecKeyRef)CFArrayGetValueAtIndex(out, 0);
|
|
||||||
if (unlikely_log(ret==NULL)){
|
|
||||||
CFRelease(out);
|
|
||||||
return PSYNC_INVALID_RSA;
|
|
||||||
}
|
|
||||||
CFRetain(ret);
|
|
||||||
CFRelease(out);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void PKCS5_PBKDF2_HMAC_SHA1(const char *pass, size_t passlen, const unsigned char *salt, size_t saltlen,
|
|
||||||
unsigned long cnt, size_t keylen, unsigned char *out){
|
|
||||||
unsigned char sha1hmacbin[CC_SHA1_DIGEST_LENGTH], itmp[4];
|
|
||||||
size_t clen;
|
|
||||||
uint32_t iter, i, j;
|
|
||||||
CCHmacContext hctx;
|
|
||||||
iter=1;
|
|
||||||
while (keylen){
|
|
||||||
if (keylen>CC_SHA1_DIGEST_LENGTH)
|
|
||||||
clen=CC_SHA1_DIGEST_LENGTH;
|
|
||||||
else
|
|
||||||
clen=keylen;
|
|
||||||
itmp[0]=(unsigned char)((iter>>24)&0xff);
|
|
||||||
itmp[1]=(unsigned char)((iter>>16)&0xff);
|
|
||||||
itmp[2]=(unsigned char)((iter>>8)&0xff);
|
|
||||||
itmp[3]=(unsigned char)(iter&0xff);
|
|
||||||
CCHmacInit(&hctx, kCCHmacAlgSHA1, pass, passlen);
|
|
||||||
CCHmacUpdate(&hctx, salt, saltlen);
|
|
||||||
CCHmacUpdate(&hctx, itmp, 4);
|
|
||||||
CCHmacFinal(&hctx, sha1hmacbin);
|
|
||||||
memcpy(out, sha1hmacbin, clen);
|
|
||||||
for (i=1; i<cnt; i++){
|
|
||||||
CCHmac(kCCHmacAlgSHA1, pass, passlen, sha1hmacbin, CC_SHA1_DIGEST_LENGTH, sha1hmacbin);
|
|
||||||
for(j=0; j<clen; j++)
|
|
||||||
out[j]^=sha1hmacbin[j];
|
|
||||||
}
|
|
||||||
out+=clen;
|
|
||||||
keylen-=clen;
|
|
||||||
iter++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
psync_symmetric_key_t psync_ssl_gen_symmetric_key_from_pass(const char *password, size_t keylen, const char *salt, size_t saltlen){
|
|
||||||
psync_symmetric_key_t key=(psync_symmetric_key_t)psync_malloc(keylen+offsetof(psync_symmetric_key_struct_t, key));
|
|
||||||
key->keylen=keylen;
|
|
||||||
PKCS5_PBKDF2_HMAC_SHA1(password, strlen(password), (const unsigned char *)salt,
|
|
||||||
saltlen, PSYNC_CRYPTO_PASS_TO_KEY_ITERATIONS, keylen, key->key);
|
|
||||||
return key;
|
|
||||||
/* CFDictionaryRef dict;
|
|
||||||
CFTypeRef keys[4], values[4];
|
|
||||||
CFStringRef pass;
|
|
||||||
SecKeyRef ret;
|
|
||||||
int num;
|
|
||||||
keys[0]=kSecAttrSalt;
|
|
||||||
values[0]=CFDataCreate(kCFAllocatorDefault, (const unsigned char *)PSYNC_CRYPTO_PASS_TO_KEY_SALT, sizeof(PSYNC_CRYPTO_PASS_TO_KEY_SALT)-1);
|
|
||||||
keys[1]=kSecAttrPRF;
|
|
||||||
values[1]=kSecAttrPRFHmacAlgSHA1;
|
|
||||||
num=PSYNC_CRYPTO_PASS_TO_KEY_ITERATIONS;
|
|
||||||
keys[2]=kSecAttrRounds;
|
|
||||||
values[2]=CFNumberCreate(NULL, kCFNumberIntType, &num);
|
|
||||||
num=keylen*8;
|
|
||||||
keys[3]=kSecAttrKeySizeInBits;
|
|
||||||
values[3]=CFNumberCreate(NULL, kCFNumberIntType, &num);
|
|
||||||
dict=CFDictionaryCreate(NULL, keys, values, ARRAY_SIZE(keys), NULL, NULL);
|
|
||||||
pass=CFStringCreateWithCStringNoCopy(NULL, password, kCFStringEncodingUTF8, NULL);
|
|
||||||
ret=SecKeyDeriveFromPassword(pass, dict, NULL);
|
|
||||||
CFRelease(pass);
|
|
||||||
CFRelease(dict);
|
|
||||||
CFRelease(values[0]);
|
|
||||||
CFRelease(values[2]);
|
|
||||||
CFRelease(values[3]);
|
|
||||||
return ret;*/
|
|
||||||
}
|
|
||||||
|
|
||||||
psync_encrypted_symmetric_key_t psync_ssl_rsa_encrypt_symmetric_key(psync_rsa_publickey_t rsa, const psync_symmetric_key_t key){
|
|
||||||
size_t elen;
|
|
||||||
psync_encrypted_symmetric_key_t ret;
|
|
||||||
OSStatus st;
|
|
||||||
elen=SecKeyGetBlockSize(rsa);
|
|
||||||
ret=(psync_encrypted_symmetric_key_t)psync_malloc(offsetof(psync_encrypted_data_struct_t, data)+elen);
|
|
||||||
st=SecKeyEncrypt(rsa, kSecPaddingOAEP, key->key, key->keylen, ret->data, &elen);
|
|
||||||
if (unlikely_log(st!=errSecSuccess)){
|
|
||||||
psync_free(ret);
|
|
||||||
return PSYNC_INVALID_ENC_SYM_KEY;
|
|
||||||
}
|
|
||||||
ret->datalen=elen;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
psync_symmetric_key_t psync_ssl_rsa_decrypt_symmetric_key(psync_rsa_privatekey_t rsa, const psync_encrypted_symmetric_key_t enckey){
|
|
||||||
unsigned char buff[2048];
|
|
||||||
size_t len;
|
|
||||||
psync_symmetric_key_t ret;
|
|
||||||
OSStatus st;
|
|
||||||
st=SecKeyDecrypt(rsa, kSecPaddingOAEP, enckey->data, enckey->datalen, buff, &len);
|
|
||||||
if (unlikely_log(st!=errSecSuccess))
|
|
||||||
return PSYNC_INVALID_SYM_KEY;
|
|
||||||
ret=(psync_symmetric_key_t)psync_malloc(offsetof(psync_symmetric_key_struct_t, key)+len);
|
|
||||||
ret->keylen=len;
|
|
||||||
memcpy(ret->key, buff, len);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
psync_aes256_encoder psync_ssl_aes256_create_encoder(psync_symmetric_key_t key){
|
|
||||||
CCCryptorRef ret;
|
|
||||||
assert(key->keylen>=PSYNC_AES256_KEY_SIZE);
|
|
||||||
if (unlikely_log(CCCryptorCreate(kCCEncrypt, kCCAlgorithmAES128, kCCOptionECBMode, key->key, PSYNC_AES256_KEY_SIZE, NULL, &ret)!=kCCSuccess))
|
|
||||||
return PSYNC_INVALID_ENCODER;
|
|
||||||
else
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void psync_ssl_aes256_free_encoder(psync_aes256_encoder aes){
|
|
||||||
CCCryptorRelease(aes);
|
|
||||||
}
|
|
||||||
|
|
||||||
psync_aes256_encoder psync_ssl_aes256_create_decoder(psync_symmetric_key_t key){
|
|
||||||
CCCryptorRef ret;
|
|
||||||
assert(key->keylen>=PSYNC_AES256_KEY_SIZE);
|
|
||||||
if (unlikely_log(CCCryptorCreate(kCCDecrypt, kCCAlgorithmAES128, kCCOptionECBMode, key->key, PSYNC_AES256_KEY_SIZE, NULL, &ret)!=kCCSuccess))
|
|
||||||
return PSYNC_INVALID_ENCODER;
|
|
||||||
else
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void psync_ssl_aes256_free_decoder(psync_aes256_encoder aes){
|
|
||||||
CCCryptorRelease(aes);
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue