📄 pubcrypt.c
字号:
/* * Following codes(particularly check_secure_directory function) * are derived from * ``Secure Programming Cookbook for C and C++''. * URL:http://www.oreilly.com/catalog/secureprgckbk/ * http://www.secureprogramming.com/ * * Licensing Information can be obtain from following URL: * * http://www.secureprogramming.com/?action=license * * Copyright 2003 by John Viega and Matt Messier. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. 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. * * 3. Neither the name of the developer of this software 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 THE COPYRIGHT * OWNER OR CONTRIBUTORS 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 <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>#include <string.h>#include <dirent.h>#include <glib.h>#include <openssl/bn.h>#include <openssl/sha.h>#include <openssl/md5.h>#include <openssl/rsa.h>#include <openssl/engine.h>#include <openssl/err.h>#include <openssl/rand.h>#include <openssl/pem.h>#include "common.h"GStaticMutex dir_check_mutex = G_STATIC_MUTEX_INIT;GStaticMutex file_check_mutex = G_STATIC_MUTEX_INIT;GStaticMutex rsa_key_mutex = G_STATIC_MUTEX_INIT;static RSA *rsa_keys[RSA_KEY_MAX];static int key2ipmsg_key_type[]={ IPMSG_RSA_2048, IPMSG_RSA_1024, IPMSG_RSA_512, -1};static intget_rsa_key_index(unsigned long cap,int *indp){ int rc; int index; if ( (!indp) || (!(cap & RSA_CAPS)) ) return -EINVAL; switch(cap) { case IPMSG_RSA_512: index=RSA_KEY_INDEX_512; break; case IPMSG_RSA_1024: index=RSA_KEY_INDEX_1024; break; case IPMSG_RSA_2048: index=RSA_KEY_INDEX_2048; break; default: g_assert_not_reached(); break; } *indp=index; return 0;}static intopen_key_file_for_read(int *fd_p,const unsigned char *file) { int rc; int fd; uid_t uid; struct stat fbuff,lbuff; if ( (!fd_p) || (!file) ) return -EINVAL; g_static_mutex_lock(&file_check_mutex); /* 厳密にいえば不要 */ fd=open(file,O_RDONLY); if (fd<0) { rc=-errno; goto unlock_out; } rc=fstat(fd,&fbuff); if (rc<0) { rc=-errno; goto error_out; } rc=lstat(file,&lbuff); if (rc<0) { rc=-errno; goto error_out; } uid=geteuid(); /* * 偏執的ではあるが, リンクでないことを確認する */ rc=-EPERM; if ( (lbuff.st_mode != fbuff.st_mode) || (lbuff.st_ino != fbuff.st_ino) || (lbuff.st_dev != fbuff.st_dev) ) goto error_out; /* * 本人以外に書き込めないことを確認する */ if ( ((fbuff.st_mode) & RSA_DIR_INVALID_FLAGS)) goto error_out; /* * rootが所有するファイルには, 書き込まない */ if ( (fbuff.st_uid) && (fbuff.st_uid != uid) ) goto error_out; rc=0; *fd_p=fd; unlock_out: g_static_mutex_unlock(&file_check_mutex); /* 厳密にいえば不要 */ return rc; error_out: close(fd); g_static_mutex_unlock(&file_check_mutex); /* 厳密にいえば不要 */ return rc;}static intopen_key_file_for_write(int *fd_p,const unsigned char *file) { int rc; int fd; uid_t uid; struct stat fbuff,lbuff; if ( (!fd_p) || (!file) ) return -EINVAL; g_static_mutex_lock(&file_check_mutex); /* 厳密にいえば不要 */ fd=open(file,O_CREAT|O_EXCL|O_WRONLY,S_IRUSR|S_IWUSR); if (fd<0){ if (errno != EEXIST) { rc=-errno; goto unlock_out; }else{ fd=open(file, O_WRONLY); if (fd<0){ rc=-errno; goto unlock_out; } } } rc=fstat(fd,&fbuff); if (rc<0) { rc=-errno; goto error_out; } rc=lstat(file,&lbuff); if (rc<0) { rc=-errno; goto error_out; } uid=geteuid(); /* * 偏執的ではあるが, リンクでないことを確認する */ rc=-EPERM; if ( (lbuff.st_mode != fbuff.st_mode) || (lbuff.st_ino != fbuff.st_ino) || (lbuff.st_dev != fbuff.st_dev) ) goto error_out; /* * 本人以外に書き込めないことを確認する */ if ( ((fbuff.st_mode) & RSA_DIR_INVALID_FLAGS)) goto error_out; /* * rootが所有するファイルには, 書き込まない */ if ( (fbuff.st_uid) && (fbuff.st_uid != uid) ) goto error_out; rc=0; *fd_p=fd; unlock_out: g_static_mutex_unlock(&file_check_mutex); /* 厳密にいえば不要 */ return rc; error_out: close(fd); g_static_mutex_unlock(&file_check_mutex); /* 厳密にいえば不要 */ return rc;}static intcheck_secure_directory(const unsigned char *dir) { DIR *fd,*start; int rc; char new_dir[PATH_MAX+1]; uid_t uid; struct stat fbuff,lbuff; void *ref; g_static_mutex_lock(&dir_check_mutex); /* 厳密にいえば不要 */ start = opendir("."); if (!start) { rc=-errno; goto unlock_out; } rc=lstat(dir,&lbuff); if (rc<0) { rc=-errno; goto close_dir_out; } uid=geteuid(); do{ if (chdir(dir)) { rc=-errno; goto ret_to_work_dir_out; } fd=opendir("."); if (!fd) goto ret_to_work_dir_out; rc=fstat(dirfd(fd),&fbuff); closedir(fd); if (rc<0) { rc=-errno; goto ret_to_work_dir_out; } /* * 偏執的ではあるが, リンクでないことを確認する */ rc=-EPERM; if ( (lbuff.st_mode != fbuff.st_mode) || (lbuff.st_ino != fbuff.st_ino) || (lbuff.st_dev != fbuff.st_dev) ) goto ret_to_work_dir_out; /* * 本人以外に書き込めないことを確認する */ if ( ((fbuff.st_mode) & RSA_DIR_INVALID_FLAGS)) goto ret_to_work_dir_out; /* * rootが所有するファイルには, 書き込まない */ if ( (fbuff.st_uid) && (fbuff.st_uid != uid) ) goto ret_to_work_dir_out; /* *1つ上のディレクトリを探査する */ dir=".."; rc=lstat(dir,&lbuff); if (rc<0) { rc=-errno; goto ret_to_work_dir_out; } memset(new_dir,0,PATH_MAX+1); ref=getcwd(new_dir,PATH_MAX+1); /* 次に調査するディレクトリの * 親ディレクトリを獲得 */ if (!ref) goto ret_to_work_dir_out; }while(new_dir[1]); if (!new_dir[1]) rc=0; else rc=-EPERM; ret_to_work_dir_out: fchdir(dirfd(start)); close_dir_out: closedir(start); unlock_out: g_static_mutex_unlock(&dir_check_mutex); /* 厳密にいえば不要 */ return rc;}static intstore_private_key(const char *fpath,RSA *rsa,pem_password_cb *cb){ int rc; int fd; FILE *fp; EVP_CIPHER *enc=NULL; char errbuf[1024]; if ( (!fpath) || (!rsa) ) return -EINVAL; rc=open_key_file_for_write(&fd,fpath); if (rc) goto error_out; fp=fdopen(fd,"w"); if (!fp) { rc=-errno; goto error_out; } if (cb) enc=(EVP_CIPHER *)EVP_des_ede_cbc(); rc=PEM_write_RSAPrivateKey(fp,rsa,enc,NULL,0,cb,NULL); if (!rc){ rc=ERR_get_error(); err_out("Can not store private key %s : err=%s\n", fpath, ERR_error_string(rc, errbuf)); rc=-rc; } rc=fclose(fp); if (rc) rc=-errno; rc=0; error_out: return rc;}static intstore_public_key(const char *fpath,RSA *rsa){ int rc; int fd; FILE *fp; EVP_CIPHER *enc=NULL; char errbuf[1024]; if ( (!fpath) || (!rsa) ) return -EINVAL; rc=open_key_file_for_write(&fd,fpath); if (rc<0) goto error_out; fp=fdopen(fd,"w"); if (!fp) { rc=-errno; goto error_out; } rc=PEM_write_RSAPublicKey(fp,rsa); if (!rc){ rc=ERR_get_error(); err_out("Can not store public key %s : err=%s\n", fpath, ERR_error_string(rc, errbuf)); rc=-rc; } rc=fclose(fp); if (rc) rc=-errno; rc=0; error_out: return rc;}static intload_private_key(const char *fpath,RSA **rsa,pem_password_cb *cb){ int rc; int fd; FILE *fp; char errbuf[1024]; void *ref; if ( (!fpath) || (!rsa) ) return -EINVAL; rc=open_key_file_for_read(&fd,fpath); if (rc) goto error_out; fp=fdopen(fd,"r"); if (!fp) { rc=-errno; goto error_out; } ref=PEM_read_RSAPrivateKey(fp,rsa,cb,NULL); if (!ref){ rc=ERR_get_error(); err_out("Can not load private key %s : err=%s\n", fpath, ERR_error_string(rc, errbuf)); rc=-rc; } rc=fclose(fp); if (rc) rc=-errno; rc=0; error_out: return rc;}static intload_public_key(const char *fpath,RSA **rsa){ int rc; int fd; FILE *fp; EVP_CIPHER *enc=NULL; char errbuf[1024]; RSA *ref; if ( (!fpath) || (!rsa) ) return -EINVAL; rc=open_key_file_for_read(&fd,fpath); if (rc) goto error_out; fp=fdopen(fd,"r"); if (!fp) { rc=-errno; goto error_out; } ref=PEM_read_RSAPublicKey(fp,rsa,NULL,NULL); if (!ref){ rc=ERR_get_error(); err_out("Can not read public key %s : err=%s\n", fpath, ERR_error_string(rc, errbuf)); rc=-rc; } rc=fclose(fp); if (rc) rc=-errno; rc=0; error_out: return rc;}static int generate_rsa_key(RSA **rsa_p,unsigned long key_type) { int rc; RSA *rsa; char errbuf[1024]; int keylen; int retry_count=RSA_KEYGEN_RETRY; if (!rsa_p) return -EINVAL; rc=pcrypt_get_rsa_key_length(key_type,&keylen); if (rc) return rc; dbg_out("generate key length:%d\n",keylen); /* RSA 鍵生成 */ retry: rsa = RSA_generate_key(keylen, RSA_F4, NULL, NULL); if ( rsa == NULL ){ rc=ERR_get_error(); dbg_out("in generate_key: err=%s\n", ERR_error_string(rc, errbuf)); return (ERR_get_error()*-1); } if (RSA_check_key(rsa)>0){ *rsa_p=rsa; rc=0; } else { RSA_free(rsa); rc=ERR_get_error(); err_out("This is invalid key: err=%s\n", ERR_error_string(rc, errbuf)); --retry_count; if (retry_count) goto retry; } return rc;}static intconvert_peer_key(const char *peer_e,const char *peer_n,RSA **rsa){ int rc; RSA *pubkey=NULL; BIGNUM *bn_e=NULL,*bn_n=NULL; size_t size_in_byte; if ( (!peer_e) || (!peer_n) || (!rsa) ) return -EINVAL; pubkey = RSA_new(); if (!pubkey) return -ENOMEM; rc=-ENOMEM; bn_e = BN_new(); if (!bn_e) goto free_pubkey_out; bn_n = BN_new(); if (!bn_n) goto free_bn_e_out; rc=BN_hex2bn(&bn_e, peer_e); if (!rc) goto free_bn_e_out; rc=BN_hex2bn(&bn_n, peer_n); if (!rc) goto free_bn_e_out;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -