網頁

2017年8月30日 星期三

SSL 網路程式設計

請參考 Raspberry OPENSSL 根證書 伺服端 客戶端 產生所有需要的檔案

sudo apt-get install libssl-dev

伺服器端程式
gcc server.c -o server -lcrypto -lssl
vi server.c
#include "openssl/bio.h"  
#include "openssl/ssl.h"  
#include "openssl/err.h" 

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

#define SERVER_PORT 8080
#define CA_CERT_FILE "../openssl/ca/ca.crt"
#define SERVER_CERT_FILE "../openssl/server/server.crt"
#define SERVER_KEY_FILE "../openssl/server/server.key"

typedef struct sockaddr SA;

int TcpInit()
{
    int listener;
    do{
        listener = socket(AF_INET, SOCK_STREAM, 0);
        if( listener == -1 )
            return 0;

        struct sockaddr_in sin;
        sin.sin_family = AF_INET;
        sin.sin_addr.s_addr = 0;
        sin.sin_port = htons(SERVER_PORT);

        if( bind(listener, (SA*)&sin, sizeof(sin)) < 0 )
            break;

        if( listen(listener, 5) < 0)
            break;

        return listener;
    }while(0);

    return -1;
}

void print_peer_certificate(SSL *ssl)
{  
    X509* cert= NULL;  
    X509_NAME *name=NULL;  
    char buf[8192]={0};  
    BIO *bio_cert = NULL;  
    cert = SSL_get_peer_certificate(ssl);
    if (cert == NULL) {
        printf("SSL_get_peer_certificate() == NULL\n");  
        return;
    }
    if (SSL_get_verify_result(ssl) == X509_V_OK) {
        printf("SSL_get_verify_result(ssl) == X509_V_OK\n");  
    }
    name = X509_get_subject_name(cert);  
    X509_NAME_oneline(name,buf,8191);  
    printf("ServerSubjectName:%s\n",buf);  
    memset(buf,0,sizeof(buf));  
    bio_cert = BIO_new(BIO_s_mem());  
    PEM_write_bio_X509(bio_cert, cert);  
    BIO_read( bio_cert, buf, 8191);  
    printf("SERVER CERT:\n%s\n",buf);  
    if(bio_cert)BIO_free(bio_cert);  
    if(cert)X509_free(cert);  
}


static int verify_cb(int res, X509_STORE_CTX *xs)  
{  
    printf("SSL VERIFY RESULT :%d\n",res);  
    switch (xs->error)  
    {  
        case X509_V_ERR_UNABLE_TO_GET_CRL:  
            printf(" NOT GET CRL!\n");  
            return 1;  
        default :  
            break;  
    }  
    return res;  
}

int main(int argc, char **argv)  
{  
    SSL_CTX     *ctx;  
    SSL         *ssl;  
    X509        *client_cert;  
    char szBuffer[1024];  
    int nLen;  
    struct sockaddr_in addr;   
    int nListenFd, nAcceptFd;  

    nListenFd = TcpInit();
    SSLeay_add_ssl_algorithms();  
    OpenSSL_add_all_algorithms();  
    SSL_load_error_strings();  
    ERR_load_BIO_strings();  

    memset(&addr, 0, sizeof(addr));
    int len = sizeof(addr);
    nAcceptFd = accept(nListenFd, (struct sockaddr *)&addr, &len);   
    //int iMode = 1;
    //int iret = ioctlsocket(nAcceptFd, FIONBIO, (u_long FAR*)&iMode); 
    ctx = SSL_CTX_new (SSLv23_method());
    if( ctx == NULL)
    {
        printf("SSL_CTX_new error!\n");
        return -1;
    }

#define USE_CA_CERT
#ifdef USE_CA_CERT
// 使用 CA_CERT_FILE 檢查 Client 端的證書
    printf("SSL_CTX_set_verify(SSL_VERIFY_PEER)\n");
    SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verify_cb);  

    if(!SSL_CTX_load_verify_locations(ctx, CA_CERT_FILE, NULL))
    {
        printf("SSL_CTX_load_verify_locations error!\n");
        ERR_print_errors_fp(stderr);
        return -1;
    }
#else
    printf("SSL_CTX_set_verify(SSL_VERIFY_NONE)\n");
    SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);  
#endif

    if(SSL_CTX_use_certificate_file(ctx, SERVER_CERT_FILE, SSL_FILETYPE_PEM) <= 0)
    {
        printf("SSL_CTX_use_certificate_file error!\n");
        ERR_print_errors_fp(stderr);
        return -1;
    }

    if(SSL_CTX_use_PrivateKey_file(ctx, SERVER_KEY_FILE, SSL_FILETYPE_PEM) <= 0)
    {
        printf("SSL_CTX_use_PrivateKey_file error!\n");
        ERR_print_errors_fp(stderr);
        return -1;
    }

    if(!SSL_CTX_check_private_key(ctx))
    {
        printf("SSL_CTX_check_private_key error!\n");
        ERR_print_errors_fp(stderr);
        return -1;
    }
    ssl = SSL_new (ctx);
    if(!ssl)
    {
        printf("SSL_new error!\n");
        ERR_print_errors_fp(stderr);
        return -1;
    }
    SSL_set_fd (ssl, nAcceptFd); 
    while(1){
        if(SSL_accept (ssl) != 1)
        {
            int icode = -1;
            ERR_print_errors_fp(stderr);
            int iret = SSL_get_error(ssl, icode);
            printf("SSL_accept error! code = %d, iret = %d\n", icode, iret);
            break;
        } else
            break;
    }
    print_peer_certificate(ssl);

    memset(szBuffer, 0, sizeof(szBuffer));  
    nLen = SSL_read(ssl,szBuffer, sizeof(szBuffer));  
    fprintf(stderr, "Get Len %d %s ok\n", nLen, szBuffer);  
    strcat(szBuffer, "\n this is from server========server resend to client");  
    SSL_write(ssl, szBuffer, strlen(szBuffer));  

    SSL_free (ssl);  
    SSL_CTX_free (ctx);  
    close(nAcceptFd);  
}

客戶端程式
gcc client.c -o client -lcrypto -lssl
vi client.c
#include "openssl/bio.h"  
#include "openssl/ssl.h"  
#include "openssl/err.h" 


#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

#define SERVER_PORT 8080
#define SERVER_IP "127.0.0.1"


#define CA_CERT_FILE "../openssl/ca/ca.crt"
#define CLIENT_CERT_FILE "../openssl/client/client.crt"
#define CLIENT_KEY_FILE "../openssl/client/client.key"

void print_client_cert(char* path)  
{  
    X509 *cert =NULL;  
    FILE *fp = NULL;  
    fp = fopen(path,"rb");  
    cert = PEM_read_X509(fp, NULL, NULL, NULL);  
    X509_NAME *name=NULL;  
    char buf[8192]={0};  
    BIO *bio_cert = NULL;  
    name = X509_get_subject_name(cert);  
    X509_NAME_oneline(name,buf,8191);  
    printf("ClientSubjectName:%s\n",buf);  
    memset(buf,0,sizeof(buf));  
    bio_cert = BIO_new(BIO_s_mem());  
    PEM_write_bio_X509(bio_cert, cert);  
    BIO_read( bio_cert, buf, 8191);  
    printf("CLIENT CERT:\n%s\n",buf);  
    if(bio_cert)BIO_free(bio_cert);  
    fclose(fp);  
    if(cert) X509_free(cert);  
}

void print_peer_certificate(SSL *ssl)  
{  
    X509* cert= NULL;  
    X509_NAME *name=NULL;  
    char buf[8192]={0};  
    BIO *bio_cert = NULL;  
    cert = SSL_get_peer_certificate(ssl);
    if (cert == NULL) {
        printf("SSL_get_peer_certificate() == NULL\n");
        return;
    }
    if (SSL_get_verify_result(ssl) == X509_V_OK) {
        printf("SSL_get_verify_result(ssl) == X509_V_OK\n");  
    }
    name = X509_get_subject_name(cert);  
    X509_NAME_oneline(name,buf,8191);  
    printf("ServerSubjectName:%s\n",buf);  
    memset(buf,0,sizeof(buf));  
    bio_cert = BIO_new(BIO_s_mem());  
    PEM_write_bio_X509(bio_cert, cert);  
    BIO_read( bio_cert, buf, 8191);  
    printf("SERVER CERT:\n%s\n",buf);  
    if(bio_cert)BIO_free(bio_cert);  
    if(cert)X509_free(cert);  
}

static int verify_cb(int res, X509_STORE_CTX *xs)  
{  
    printf("SSL VERIFY RESULT :%d\n",res);  
    switch (xs->error)  
    {  
        case X509_V_ERR_UNABLE_TO_GET_CRL:  
            printf(" NOT GET CRL!\n");  
            return 1;  
        default :  
            break;  
    }  
    return res;  
}

int main(int argc, char **argv)  
{  
    char *address = SERVER_IP;

    if(argc > 1)
    {
        address = argv[1];
    }

    SSL_METHOD  *meth;  
    SSL_CTX     *ctx;  
    SSL         *ssl;  

    int nFd;  
    int nLen;  
    char szBuffer[1024];  

    SSLeay_add_ssl_algorithms();  
    OpenSSL_add_all_algorithms();  
    SSL_load_error_strings();  
    ERR_load_BIO_strings();  

    print_client_cert(CLIENT_CERT_FILE);

    // 使用SSL V3,V2  
    ctx = SSL_CTX_new (SSLv23_method());
    if( ctx == NULL)
    {
        printf("SSL_CTX_new error!\n");
        ERR_print_errors_fp(stderr);
        return -1;
    }

#define USE_CA_CERT
#ifdef USE_CA_CERT
// 使用 CA_CERT_FILE 檢查 Server 端的證書
    printf("SSL_CTX_set_verify(SSL_VERIFY_PEER)\n");
    SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_cb);  

    if(!SSL_CTX_load_verify_locations(ctx, CA_CERT_FILE, NULL))
    {
        printf("SSL_CTX_load_verify_locations error!\n");
        ERR_print_errors_fp(stderr);
        return -1;
    }
#else
    printf("SSL_CTX_set_verify(SSL_VERIFY_NONE)\n");
    SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);  
#endif

#define USE_CERT
#ifdef USE_CERT
    printf("SSL_CTX_use_certificate_file start!\n");
    if(SSL_CTX_use_certificate_file(ctx, CLIENT_CERT_FILE, SSL_FILETYPE_PEM) <= 0)
    {
        printf("SSL_CTX_use_certificate_file error!\n");
        ERR_print_errors_fp(stderr);
        return -1;
    }

    printf("SSL_CTX_use_PrivateKey_file start!\n");
    if(SSL_CTX_use_PrivateKey_file(ctx, CLIENT_KEY_FILE, SSL_FILETYPE_PEM) <= 0)
    {
     printf("SSL_CTX_use_PrivateKey_file error!\n");
     ERR_print_errors_fp(stderr);
     return -1;
    }

    if(!SSL_CTX_check_private_key(ctx))
    {
     printf("SSL_CTX_check_private_key error!\n");
     ERR_print_errors_fp(stderr);
     return -1;
    }
#endif

    nFd = socket(AF_INET, SOCK_STREAM, 0); 

    struct sockaddr_in addr; 
    addr.sin_addr.s_addr = inet_addr(address);
    addr.sin_family = AF_INET;
    addr.sin_port = htons(SERVER_PORT);

    if(connect(nFd, (struct sockaddr *)&addr, sizeof(addr)) < 0)  
    {  
        printf("connect\n"); 
        ERR_print_errors_fp(stderr);
        return -1;  
    }  

    ssl = SSL_new (ctx);
    if( ssl == NULL)
    {
        printf("SSL_new error!\n");
        ERR_print_errors_fp(stderr);
        return -1;
    }
    SSL_set_fd (ssl, nFd);  
    if( SSL_connect (ssl) != 1)
    {
        printf("SSL_new error!\n");
        ERR_print_errors_fp(stderr);
        return -1;
    }

    print_peer_certificate(ssl);

    sprintf(szBuffer, "\nthis is from client+++++++++++++++client send to server");  
    SSL_write(ssl, szBuffer, strlen(szBuffer));  

    memset(szBuffer, 0, sizeof(szBuffer));  
    nLen = SSL_read(ssl,szBuffer, sizeof(szBuffer));  
    fprintf(stderr, "Get Len %d %s ok\n", nLen, szBuffer);  

    SSL_free (ssl);  
    SSL_CTX_free (ctx);  
    close(nFd);     
}



2017年8月29日 星期二

Raspberry OPENSSL 根證書 伺服端 客戶端

準備設定檔
pi@raspberrypi:~/OpenSSL/openssl $ cp /etc/ssl/openssl.cnf .
pi@raspberrypi:~/OpenSSL/openssl $ mkdir ca server client
pi@raspberrypi:~/OpenSSL/openssl $
產生根私鑰
pi@raspberrypi:~/OpenSSL/openssl $ openssl genrsa -out ca/ca.key 2048
Generating RSA private key, 2048 bit long modulus
..............................................................................................+++
......+++
e is 65537 (0x10001)
產生根證書
pi@raspberrypi:~/OpenSSL/openssl $ openssl req -new -x509 -key ca/ca.key -out ca
/ca.crt -days 3650
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:TW
State or Province Name (full name) [Some-State]:Taiwan
Locality Name (eg, city) []:Taichung
Organization Name (eg, company) [Internet Widgits Pty Ltd]:SDL
Organizational Unit Name (eg, section) []:R&D
Common Name (e.g. server FQDN or YOUR name) []:PiCA
Email Address []:
pi@raspberrypi:~/OpenSSL/openssl $ ls ca
ca.crt  ca.key
pi@raspberrypi:~/OpenSSL/openssl $
產生伺服端私鑰
pi@raspberrypi:~/OpenSSL/openssl $ openssl genrsa -out server/server.key 2048
Generating RSA private key, 2048 bit long modulus
.............................+++
..............+++
e is 65537 (0x10001)
產生伺服端需求證書
pi@raspberrypi:~/OpenSSL/openssl $ openssl req -new -key server/server.key -out server/server.csr
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:TW
State or Province Name (full name) [Some-State]:Taiwan
Locality Name (eg, city) []:Taichung
Organization Name (eg, company) [Internet Widgits Pty Ltd]:SDL
Organizational Unit Name (eg, section) []:R&D
Common Name (e.g. server FQDN or YOUR name) []:PiServer
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
pi@raspberrypi:~/OpenSSL/openssl $ ls server/
server.csr  server.key
pi@raspberrypi:~/OpenSSL/openssl $
產生客戶端私鑰
pi@raspberrypi:~/OpenSSL/openssl $ openssl genrsa -out client/client.key 2048
Generating RSA private key, 2048 bit long modulus
..............................................+++
....................................+++
e is 65537 (0x10001)
產生客戶端需求證書
pi@raspberrypi:~/OpenSSL/openssl $ openssl req -new -key client/client.key -out
client/client.csr
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:TW
State or Province Name (full name) [Some-State]:Taiwan
Locality Name (eg, city) []:Taichung
Organization Name (eg, company) [Internet Widgits Pty Ltd]:SDL
Organizational Unit Name (eg, section) []:R&D
Common Name (e.g. server FQDN or YOUR name) []:PiClient
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
pi@raspberrypi:~/OpenSSL/openssl $ ls client/
client.csr  client.key
pi@raspberrypi:~/OpenSSL/openssl $
修改 dir 目錄
pi@raspberrypi:~/OpenSSL/openssl $ vi openssl.cnf
[ CA_default ]

#dir            = ./demoCA              # Where everything is kept
dir             = .             # Where everything is kept
certs           = $dir/certs            # Where the issued certs are kept
crl_dir         = $dir/crl              # Where the issued crl are kept
database        = $dir/index.txt        # database index file.
#unique_subject = no                    # Set to 'no' to allow creation of
pi@raspberrypi:~/OpenSSL/openssl $
簽署證書環境準備
pi@raspberrypi:~/OpenSSL/openssl $ touch index.txt
pi@raspberrypi:~/OpenSSL/openssl $ echo "01">serial
pi@raspberrypi:~/OpenSSL/openssl $ mkdir newcerts
簽署伺服端證書
pi@raspberrypi:~/OpenSSL/openssl $ openssl ca -in server/server.csr -out server/server.crt -days 3650 -cert ca/ca.crt -keyfile ca/ca.key -config openssl.cnf
Using configuration from openssl.cnf
Check that the request matches the signature
Signature ok
Certificate Details:
        Serial Number: 1 (0x1)
        Validity
            Not Before: Aug 29 02:08:38 2017 GMT
            Not After : Aug 27 02:08:38 2027 GMT
        Subject:
            countryName               = TW
            stateOrProvinceName       = Taiwan
            organizationName          = SDL
            organizationalUnitName    = R&D
            commonName                = PiServer
        X509v3 extensions:
            X509v3 Basic Constraints:
                CA:FALSE
            Netscape Comment:
                OpenSSL Generated Certificate
            X509v3 Subject Key Identifier:
                4D:26:A0:55:4D:37:58:EE:10:D3:A0:8E:B8:93:35:E9:E5:84:1F:BC
            X509v3 Authority Key Identifier:
                keyid:F4:6D:3E:3D:93:2A:4A:81:85:62:C3:D7:4B:70:F9:28:F6:E6:A4:F4

Certificate is to be certified until Aug 27 02:08:38 2027 GMT (3650 days)
Sign the certificate? [y/n]:y


1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated
pi@raspberrypi:~/OpenSSL/openssl $ ls server/
server.crt  server.csr  server.key
pi@raspberrypi:~/OpenSSL/openssl $
簽署客戶端證書
pi@raspberrypi:~/OpenSSL/openssl $ openssl ca -in client/client.csr -out client/
client.crt -days 3650 -cert ca/ca.crt -keyfile ca/ca.key -config openssl.cnf
Using configuration from openssl.cnf
Check that the request matches the signature
Signature ok
Certificate Details:
        Serial Number: 2 (0x2)
        Validity
            Not Before: Aug 29 02:12:26 2017 GMT
            Not After : Aug 27 02:12:26 2027 GMT
        Subject:
            countryName               = TW
            stateOrProvinceName       = Taiwan
            organizationName          = SDL
            organizationalUnitName    = R&D
            commonName                = PiClient
        X509v3 extensions:
            X509v3 Basic Constraints:
                CA:FALSE
            Netscape Comment:
                OpenSSL Generated Certificate
            X509v3 Subject Key Identifier:
                45:1F:CC:47:19:FF:37:04:7A:8D:40:B8:1E:CA:08:11:36:E0:E7:EF
            X509v3 Authority Key Identifier:
                keyid:F4:6D:3E:3D:93:2A:4A:81:85:62:C3:D7:4B:70:F9:28:F6:E6:A4:F4

Certificate is to be certified until Aug 27 02:12:26 2027 GMT (3650 days)
Sign the certificate? [y/n]:y


1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated
pi@raspberrypi:~/OpenSSL/openssl $ ls client/
client.crt  client.csr  client.key
pi@raspberrypi:~/OpenSSL/openssl $
pi@raspberrypi:~/OpenSSL/openssl $ ls
ca      index.txt       index.txt.attr.old  newcerts     serial      server
client  index.txt.attr  index.txt.old       openssl.cnf  serial.old
pi@raspberrypi:~/OpenSSL/openssl $


2017年8月23日 星期三

HDMI 開關

關閉
sudo /opt/vc/bin/tvservice -o

開啟
sudo /opt/vc/bin/tvservice -p

約可省下 20-30mA

2017年8月2日 星期三

Raspberry & DS3231 RTC

由安裝作業系統後開始
Localisation Options/I1 Chance Locale
zh_TW.UTF-8 UTF-8
Localisation Options/I2 Chance Timezone
Asia/Taipei
Interfacing Options/P5 I2C

測試 I2C 上的裝置
sudo i2cdetect -y 1

sudo vi /etc/modules
#rtc-ds3231

sudo vi /boot/config.txt
dtoverlay=i2c-rtc,ds3231

sudo apt-get update
sudo apt-get -y upgrade
sudo apt-get purge fake-hwclock
sudo apt-get -y remove fake-hwclock
sudo update-rc.d -f fake-hwclock remove
sudo systemctl stop fake-hwclock.service
sudo update-rc.d fake-hwclock disable S 6

hwclock
-r 讀取時間
-w 系統時間 寫入 RTC
-s 以 RTC 更新 系統時間
sudo hwclock -r;date '+%a %d %b %Y %02l:%M:%S %p'
ntptime

同步網路時間
sudo ntpd -s -d


開機產生的錯誤訊息
pi@raspberrypi:~ $ systemctl status systemd-modules-load.service
● systemd-modules-load.service - Load Kernel Modules
   Loaded: loaded (/lib/systemd/system/systemd-modules-load.service; static)
   Active: failed (Result: exit-code) since Thu 1970-01-01 08:00:03 CST; 47 years 6 months ago
     Docs: man:systemd-modules-load.service(8)
           man:modules-load.d(5)
  Process: 113 ExecStart=/lib/systemd/systemd-modules-load (code=exited, status=1/FAILURE)
 Main PID: 113 (code=exited, status=1/FAILURE)


alias gshutdown='gpio mode 7 out'

解決與 witty 電源控制模組衝突
vi /etc/init.d/witty
#       sudo /home/pi/WittyPi/wittyPi/runScript.sh >> /home/pi/WittyPi/wittyPi/schedule.log &
#       sudo /home/pi/WittyPi/wittyPi/syncTime.sh 5 &

vi wittyPi/utilities.sh
is_rtc_connected()
{
return 1
...
}