網頁

顯示具有 OpenSSL 標籤的文章。 顯示所有文章
顯示具有 OpenSSL 標籤的文章。 顯示所有文章

2020年2月27日 星期四

https Client and Server

建立證書
參考 OpenSSL 證書

===
自我認證 CA
$ mkdir ca; cd ca
產生私鑰
$ mkdir private
$ openssl genrsa -out private/cakey.pem 2048
產生自簽章證書
$ cp /etc/ssl/openssl.cnf .
$ vi openssl.cnf
dir = .
default_md = sha512
keyUsage = cRLSign, keyCertSign
$ openssl req -new -x509 -nodes -key private/cakey.pem -out cacert.pem \
-days 3650 -subj "/C=TW/ST=Taiwan/L=Taichung/O=SDL/OU=R&D/CN=z390-CA" \
-config openssl.cnf
顯示證書
$ openssl x509 -text -noout -in cacert.pem

===
產生網站的證書
$ mkdir web1; cd web1
產生私鑰
$ openssl genrsa -out server.key 2048
$ vi ssl.conf
[ req ]
prompt = no
default_md = sha512
default_bits = 2048
distinguished_name = dn
req_extensions = v3_req

[ dn ]
C = TW
ST = Taiwan
L = Taichung
O = SDL
OU = R&D
emailAddress = mark@localhost
CN = mark-z390-u

[ v3_req ]
basicConstraints = CA:FALSE
subjectAltName = @alt_names
subjectKeyIdentifier = hash
keyUsage = nonRepudiation, digitalSignature, keyEncipherment

[ alt_names ]
DNS.1 = localhost
DNS.2 = mark-z390-u
DNS.3 = dixx.vigorddns.com
DNS.4 = 192.168.0.101
IP.1 = 127.0.0.1
IP.2 = 192.168.0.101
$ openssl req -new -sha512 -key server.key -out server.csr -config ssl.conf
顯示需求證書
$ openssl req -text -noout -in server.csr
顯示私鑰
$ openssl rsa -out -noout -in server.key
顯示公鑰
$ openssl rsa -in server.key -pubout -out server_pub.key
$ openssl rsa -in server_pub.key -pubin -noout -text

===
使用 自我認證 CA 簽署 需求證書
回到 ca 目錄
$ mkdir newcerts
$ touch index.txt
$ echo "01">serial
$ openssl ca -in ../web1/server.csr -out ../web1/server.crt -days 3650 -extennsions v3_req -extfile ../web1/ssl.conf -config openssl.cnf

===
匯入憑證到 Windows 10
cacert.pem 改名為 cacert.crt

本機裝置 的憑證 certlm.msc
目前的使用者憑證 certmgr.msc
受信任的根憑證授權單位/憑證
按滑鼠右鍵/所有工作/匯入 選擇 cacert.crt

金鑰使用方法
Certificate Signing, Off-line CRL Signing, CRL Signing (06)

===
參考 OCSP & CRL 介紹
CRL(Certificate Revocation List) 被 CA 撤銷的憑證清單
OCSP(Online Certificate Status Protocal) 線上查詢憑證狀態

參考根憑證
AAA Certificate Services
CRL 發佈點
CRL Distribution Point
URL=http://crl.comodoca.com/AAACertificateServices.crl



參考 Visual Studio(VS2017)編譯並配置C/C++-libcurl開發環境
從 https://curl.haxx.se/download.html 下載 curl-7.68.0.zip
解壓縮後進入 curl 目錄
執行 buildconf.bat
以 x86 為例(64為原則改為 x64)
開始/Visual Studio 2017/x86 Native Tools Command Prompt for VS 2017
按滑鼠右鍵選擇 Run as administrator
進入 curl/winbuild
nmake /f Makefile.vc mode=static VC=15 MACHINE=x86 DEBUG=yes
nmake /f Makefile.vc mode=static VC=15 MACHINE=x86 DEBUG=no
編譯的結果在 builds 下


Visual Studio 使用 libcurl
Configuration Properties/C/C++/Preprocessor/Preprocessor Definitions 加入 CURL_STATICLIB
#include <curl/curl.h>
加入下列 library
libcurl_a.lib(libcurl_a_debug.lib)
Ws2_32.lib
Wldap32.lib
winmm.lib(似乎不用)
Crypt32.lib
Normaliz.lib

form 使用
curl_easy_setopt(curl, CURLOPT_MIMEPOST, form);
json 使用
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, strU8);
curl_easy_setopt(curl, CURLOPT_POST, 1);

libcurl 之傳送接收使用  UTF-8, 函數之參數使用 Big5
在 vc 上使用 CStringA 儲存 Big5 和 UTF-8, 轉換要經過 CStringW (Unicode)

curl 之 --tlsv1.3 等於
curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_3);

curl 之 --insecure 等於
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
不使用 --insecure 等於
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, true);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2); // 0 不檢查 host
curl_easy_setopt(curl, CURLOPT_CAINFO, "cacert.pem");

curl 之 --ssl-no-revoke 等於
curl_easy_setopt(curl, CURLOPT_SSL_OPTIONS, CURLSSLOPT_NO_REVOKE);



使用 curl 測試
===
在 windows 下,引號不能使用'要使用"
--insecure 不檢查證書
===
D:\temp\aaa>curl.exe -v https://dixx.vigorddns.com:5000/api/Json -X
POST -H "Content-Type:application/json" -d "{\"updDate\":\"aaa\", \"camera\":\"b
bb\", \"ipaddress\":\"ccc\", \"addr\":\"ddd\"}" --insecure
*   Trying 114.35.104.33:5000...
* TCP_NODELAY set
* Connected to dixx.vigorddns.com (114.35.104.33) port 5000 (#0)
* schannel: next InitializeSecurityContext failed: SEC_E_INVALID_TOKEN (0x800903
08) - 提供給功能的權杖不正確
* Closing connection 0
* schannel: shutting down SSL/TLS connection with dixx.vigorddns.com por
t 5000
curl: (35) schannel: next InitializeSecurityContext failed: SEC_E_INVALID_TOKEN
(0x80090308) - 提供給功能的權杖不正確

===
Windows 7 要加上 --tlsv1.3
Windows 10 不用
===
D:\temp\aaa>curl.exe -v https://dixx.vigorddns.com:5000/api/Json -X
POST -H "Content-Type:application/json" -d "{\"updDate\":\"aaa\", \"camera\":\"b
bb\", \"ipaddress\":\"ccc\", \"addr\":\"ddd\"}" --insecure --tlsv1.3


D:\temp\aaa>curl.exe -v https://dixx.vigorddns.com:5000/api/Json -X
POST -H "Content-Type:application/json" -d "{\"updDate\":\"aaa\", \"camera\":\"b
bb\", \"ipaddress\":\"ccc\", \"addr\":\"ddd\"}" --tlsv1.3
Note: Unnecessary use of -X or --request, POST is already inferred.
*   Trying 114.35.104.33:5000...
* TCP_NODELAY set
* Connected to dixx.vigorddns.com (114.35.104.33) port 5000 (#0)
* schannel: next InitializeSecurityContext failed: Unknown error (0x80092012) -
撤銷功能無法檢查憑證的撤銷。
* Closing connection 0
* schannel: shutting down SSL/TLS connection with dixx.vigorddns.com por
t 5000
curl: (35) schannel: next InitializeSecurityContext failed: Unknown error (0x800
92012) - 撤銷功能無法檢查憑證的撤銷。

===
要檢查證書,用參數 --cacert 傳入證書檔
===
D:\temp\aaa>curl.exe -v https://dixx.vigorddns.com:5000/api/Json -X
POST -H "Content-Type:application/json" -d "{\"updDate\":\"aaa\", \"camera\":\"b
bb\", \"ipaddress\":\"ccc\", \"addr\":\"ddd\"}" --tlsv1.3 --cacert cacert.pem
Note: Unnecessary use of -X or --request, POST is already inferred.
*   Trying 114.35.104.33:5000...
* TCP_NODELAY set
* Connected to dixx.vigorddns.com (114.35.104.33) port 5000 (#0)
* schannel: added 1 certificate(s) from CA file 'cacert.pem'
* schannel: CertGetCertificateChain trust error CERT_TRUST_REVOCATION_STATUS_UNK
NOWN 0x00000040
* Closing connection 0
* schannel: shutting down SSL/TLS connection with dixx.vigorddns.com por
t 5000
curl: (60) schannel: CertGetCertificateChain trust error CERT_TRUST_REVOCATION_S
TATUS_UNKNOWN 0x00000040
More details here: https://curl.haxx.se/docs/sslcerts.html

curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.

===
因檢查證書時,會去檢查證書是否已經撤銷
--ssl-no-revoke 避免檢查
===
D:\temp\aaa>curl.exe -v https://dixx.vigorddns.com:5000/api/Json -X
POST -H "Content-Type:application/json" -d "{\"updDate\":\"aaa\", \"camera\":\"b
bb\", \"ipaddress\":\"ccc\", \"addr\":\"ddd\"}" --tlsv1.3 --cacert cacert.pem --
ssl-no-revoke

===
使用 form
D:\temp\aaa>curl.exe -v https://dixx.vigorddns.com:5000/api/SendForm
-X POST -d "location=aaa&dt=bbb&text=ccc&camera_name=eee&X=x&Y=y&plateId=ddd" --
tlsv1.3 --cacert cacert.pem --ssl-no-revoke

2019年10月9日 星期三

windows 10 憑證管理

本機裝置 的憑證 certlm.msc
目前的使用者憑證 certmgr.msc

參考格式 Create and assign SCEP certificate profiles in Intune 填寫 Subject
如: "DigiChance11,E=ing@yahoo.com,OU=Mark Chen,O=R&D,L=Taichung,S=Taiwan,C=TW"

CertFindCertificateInStore X509_ASN_ENCODING CERT_FIND_SHA1_HASH
對應 憑證指紋

2017年9月5日 星期二

SSL, RaspberryPi Server, Android Client

請參考 Android 與 Raspberry 證書 和 SSL 網路程式設計 的 Server 端
在此提供 Android 的 Client

package com.example.mark.sslclient;

import android.content.Context;
import android.content.res.AssetManager;
import android.util.Log;

import java.io.IOException;
import java.io.InputStream;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;

/** * Created by mark on 2017/9/1. */
public class SSLClient {
    static SSLContext ssl_ctx;

    public SSLClient(Context context) {
        try {
            Log.d("SSLClient", "SSLClient");

            //  Setup truststore            KeyStore trustStore = KeyStore.getInstance("BKS");
            InputStream trustStoreStream = context.getResources().openRawResource(R.raw.android);
            trustStore.load(trustStoreStream, "store1234".toCharArray());
            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            trustManagerFactory.init(trustStore);
            Log.d("SSLClient", "Trust " + trustStore.size());
            Log.d("SSLClient", "trustManagerFactory " + trustManagerFactory.getTrustManagers().length);

            //  Setup keystore            KeyStore keyStore = KeyStore.getInstance("BKS");
            KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            InputStream keyStoreStream = context.getResources().openRawResource(R.raw.android);
            keyStore.load(keyStoreStream, "store1234".toCharArray());
            keyManagerFactory.init(keyStore, "key1234".toCharArray());
            Log.d("SSLClient", "Key " + keyStore.size());
            Log.d("SSLClient", "keyManagerFactory " + keyManagerFactory.getKeyManagers().length);

            // Setup the SSL context to use the truststore and keystore            ssl_ctx = SSLContext.getInstance("TLS");
            if (true) {
                ssl_ctx.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);
            } else {
                TrustManager tm = new X509TrustManager() {
                    public void checkClientTrusted(X509Certificate[] chain, String authTyhpe) throws CertificateException {
                    }
                    public void checkServerTrusted(X509Certificate[] chain, String authTyhpe) throws CertificateException {
                    }
                    public X509Certificate[] getAcceptedIssuers() {
                        return null;
                    }
                };
                ssl_ctx.init(null, new TrustManager[] { tm }, null);
            }
        } catch (KeyStoreException e) {
            Log.d("SSLClient", e.getMessage());
        } catch (NoSuchAlgorithmException e) {
            Log.d("SSLClient", e.getMessage());
        } catch (CertificateException e) {
            Log.d("SSLClient", e.getMessage());
        } catch (IOException e) {
            Log.d("SSLClient", e.getMessage());
        } catch (KeyManagementException e) {
            Log.d("SSLClient", e.getMessage());
        } catch (UnrecoverableKeyException e) {
            Log.d("SSLClient", e.getMessage());
        }
    }
}

package com.example.mark.sslclient;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;

import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    private SSLClient sslClient;

    private Runnable threadMain = new Runnable() {
        @Override        public void run() {
            SSLSocketFactory socketFactory = (SSLSocketFactory)sslClient.ssl_ctx.getSocketFactory();
            try {
                Log.d(TAG, "threadMain createSocket a");
                SSLSocket socket = (SSLSocket)socketFactory.createSocket("192.168.1.61", 8080);
                Log.d(TAG, "threadMain createSocket b");
                PrintWriter output = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
                BufferedReader input = new BufferedReader((new InputStreamReader(socket.getInputStream())));
                output.println("\nthis is from client+++++++++++++++client send to server");
                output.flush();
                Log.d(TAG, "threadMain input.readLine() a");
                String line = input.readLine();
                while (line != null) {
                    Log.d(TAG, line);
                    line = input.readLine();
                }
                Log.d(TAG, "threadMain input.readLine() b");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    };
    @Override    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "onCreate a");
        setContentView(R.layout.activity_main);

        sslClient = new SSLClient(this);
        Thread thread = new Thread(threadMain);
        thread.start();
        Log.d(TAG, "onCreate b");
    }
}

2017年9月4日 星期一

Android 與 Raspberry 證書

請參考先前的 Raspberry OPENSSL 根證書 伺服端 客戶端
和 Java keytool and Android

// 產生 Android 要用的 key 和 keystore
D:\SVN_Repository3\pi\Key>"C:\Program Files\Java\jdk1.7.0_67\bin\keytool.exe" -validity 3650 -genkey -v -alias android -keyalg RSA -keystore android.jks -dname "CN=AndroidClient,OU=R&D,O=SDL,L=Taichung,ST=Taiwan,c=TW" -storepass store1234 -keypass key1234
針對 CN=AndroidClient, OU=R&D, O=SDL, L=Taichung, ST=Taiwan, C=TW 產生有效期 3,650 天的 2,048 位元 RSA 金鑰組以及自我簽署憑證 (SHA256withRSA)

[儲存 android.jks]

D:\SVN_Repository3\pi\Key>
// 產生申請證書
D:\SVN_Repository3\pi\Key>"C:\Program Files\Java\jdk1.7.0_67\bin\keytool.exe" -certreq -keystore android.jks -alias android -file android.csr -storepass store1234 -keypass key1234

D:\SVN_Repository3\pi\Key>dir
 磁碟區 D 中的磁碟是 新增磁碟區
 磁碟區序號:  3AAA-91FF

 D:\SVN_Repository3\pi\Key 的目錄

2017/09/04  11:15    <DIR>          .
2017/09/04  11:15    <DIR>          ..
2017/09/04  11:15             1,086 android.csr
2017/09/04  11:14             2,231 android.jks
               2 個檔案           3,317 位元組
               2 個目錄  678,150,483,968 位元組可用

D:\SVN_Repository3\pi\Key>

// 傳送 android.csr 到 RaspberryPi, 並簽署
pi@raspberrypi:~/OpenSSL/openssl $ openssl ca -in android/android.csr -out android/android.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
The stateOrProvinceName field needed to be the same in the
CA certificate (Taiwan) and the request (Taiwan)
pi@raspberrypi:~/OpenSSL/openssl $
// 原因為編碼錯誤, 下兩個命令可以查詢, 並比較
pi@raspberrypi:~/OpenSSL/openssl $ openssl asn1parse -in androiid/android.csr
pi@raspberrypi:~/OpenSSL/openssl $ openssl asn1parse -in ca/ca.crt
// 修改設定
pi@raspberrypi:~/OpenSSL/openssl $ vi openssl.cnf
#string_mask = utf8only
string_mask = pkix
# For the CA policy
[ policy_match ]
#countryName            = match
#stateOrProvinceName    = match
#organizationName       = match
countryName             = optional
stateOrProvinceName     = optional
organizationName        = optional
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional

pi@raspberrypi:~/OpenSSL/openssl $ openssl ca -in android/android.csr -out android/android.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: 4 (0x4)
        Validity
            Not Before: Sep  4 05:46:35 2017 GMT
            Not After : Sep  2 05:46:35 2027 GMT
        Subject:
            countryName               = TW
            stateOrProvinceName       = Taiwan
            organizationName          = SDL
            organizationalUnitName    = R&D
            commonName                = AndroidClient
        X509v3 extensions:
            X509v3 Basic Constraints:
                CA:FALSE
            Netscape Comment:
                OpenSSL Generated Certificate
            X509v3 Subject Key Identifier:
                99:6F:21:B8:C1:2A:DB:03:7F:37:47:17:F5:C8:6C:10:18:B2:75:50
            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 Sep  2 05:46:35 2027 GMT (3650 days)
Sign the certificate? [y/n]:y
failed to update database
TXT_DB error number 2
// 不明原因失敗,下列為解決方法
pi@raspberrypi:~/OpenSSL/openssl $ ls newcerts/
01.pem  02.pem  03.pem
pi@raspberrypi:~/OpenSSL/openssl $ openssl ca -revoke newcerts/03.pem -config op
enssl.cnf -cert ca/ca.crt -keyfile ca/ca.key
Using configuration from openssl.cnf
Revoking Certificate 03.
Data Base Updated
pi@raspberrypi:~/OpenSSL/openssl $
// 重新簽署
pi@raspberrypi:~/OpenSSL/openssl $ openssl ca -in android/android.csr -out android/android.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: 4 (0x4)
        Validity
            Not Before: Sep  4 05:51:48 2017 GMT
            Not After : Sep  2 05:51:48 2027 GMT
        Subject:
            countryName               = TW
            stateOrProvinceName       = Taiwan
            organizationName          = SDL
            organizationalUnitName    = R&D
            commonName                = AndroidClient
        X509v3 extensions:
            X509v3 Basic Constraints:
                CA:FALSE
            Netscape Comment:
                OpenSSL Generated Certificate
            X509v3 Subject Key Identifier:
                99:6F:21:B8:C1:2A:DB:03:7F:37:47:17:F5:C8:6C:10:18:B2:75:50
            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 Sep  2 05:51:48 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 $

//將 ca.crt 和 android.crt 傳回 PC
// 安裝根證書
D:\SVN_Repository3\pi\Key>"C:\Program Files\Java\jdk1.7.0_67\bin\keytool.exe" -import -trustcacerts -v -alias ca -file ca.crt -keystore android.jks -storepass store1234
擁有者: CN=PiCA, OU=R&D, O=SDL, L=Taichung, ST=Taiwan, C=TW
發出者: CN=PiCA, OU=R&D, O=SDL, L=Taichung, ST=Taiwan, C=TW
序號: e595993377a61f60
有效期自: Tue Aug 29 09:40:37 CST 2017 到: Fri Aug 27 09:40:37 CST 2027
憑證指紋:
         MD5:  8D:94:79:EB:E6:81:8C:33:4F:BE:7C:EF:16:D3:23:28
         SHA1: 7B:DF:78:14:87:F1:C8:DA:27:91:9B:6C:B7:7C:B6:6C:3F:84:59:13
         SHA256: 38:C6:7B:DC:DB:28:EA:CC:6A:A0:38:4B:DF:D2:D6:B2:44:70:CE:B5:86:F0:DE:9B:99:49:3C:75:D6:5C:89:EB
         簽章演算法名稱: SHA256withRSA
         版本: 3

擴充套件:

#1: ObjectId: 2.5.29.35 Criticality=false
AuthorityKeyIdentifier [
KeyIdentifier [
0000: F4 6D 3E 3D 93 2A 4A 81   85 62 C3 D7 4B 70 F9 28  .m>=.*J..b..Kp.(
0010: F6 E6 A4 F4                                        ....
]
]

#2: ObjectId: 2.5.29.19 Criticality=false
BasicConstraints:[
  CA:true
  PathLen:2147483647
]

#3: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: F4 6D 3E 3D 93 2A 4A 81   85 62 C3 D7 4B 70 F9 28  .m>=.*J..b..Kp.(
0010: F6 E6 A4 F4                                        ....
]
]

信任這個憑證? [否]:  y
憑證已新增至金鑰儲存庫中
[儲存 android.jks]

D:\SVN_Repository3\pi\Key>
// 安裝證書
D:\SVN_Repository3\pi\Key>"C:\Program Files\Java\jdk1.7.0_67\bin\keytool.exe" -import -v -alias android -file android.crt -keystore android.jks -storepass store1234 -keypass key1234
憑證回覆已安裝在金鑰儲存庫中
[儲存 android.jks]

D:\SVN_Repository3\pi\Key>
// 產生 BKS 格式的 keystore
D:\SVN_Repository3\pi\Key>"C:\Program Files\Java\jdk1.7.0_67\bin\keytool.exe" -importkeystore -srckeystore android.jks -srcstorepass store1234 -destkeystore android.bks -deststoretype BKS -deststorepass store1234 -provider org.bouncycastle.jce.provider.BouncyCastleProvider
已成功匯入別名 ca 的項目。
輸入 <android> 的金鑰密碼
已成功匯入別名 android 的項目。
已完成匯入命令: 成功匯入 2 個項目,0 個項目失敗或已取消

D:\SVN_Repository3\pi\Key>dir
 磁碟區 D 中的磁碟是 新增磁碟區
 磁碟區序號:  3AAA-91FF

 D:\SVN_Repository3\pi\Key 的目錄

2017/09/04  14:39    <DIR>          .
2017/09/04  14:39    <DIR>          ..
2017/09/04  14:39             4,155 android.bks
2017/09/04  13:51             4,417 android.crt
2017/09/04  13:42             1,086 android.csr
2017/09/04  13:52             4,150 android.jks
2017/08/29  09:40             1,289 ca.crt
               5 個檔案          15,097 位元組
               2 個目錄  678,150,561,792 位元組可用

D:\SVN_Repository3\pi\Key>

Java keytool and Android

D:\SVN_Repository3\pi\Key>"C:\Program Files\Java\jdk1.7.0_67\bin\keytool.exe" -validity 3650 -genkey -v -alias server -keyalg RSA -keystore server.keystore -dname "CN=AndroidServer,OU=R&D,O=SDL,L=Taichung,ST=Taiwan,c=TW" -storepass store1234 -keypass key1234
針對 CN=AndroidServer, OU=R&D, O=SDL, L=Taichung, ST=Taiwan, C=TW 產生有效期 3,650 天的 2,048 位元 RSA 金鑰組以及自我簽署憑證 (SHA256withRSA)

[儲存 server.keystore]

D:\SVN_Repository3\pi\Key>dir
 磁碟區 D 中的磁碟是 新增磁碟區
 磁碟區序號:  3AAA-91FF

 D:\SVN_Repository3\pi\Key 的目錄

2017/08/31  13:27    <DIR>          .
2017/08/31  13:27    <DIR>          ..
2017/08/31  13:27             2,228 server.keystore
               1 個檔案           2,228 位元組
               2 個目錄  679,286,407,168 位元組可用

D:\SVN_Repository3\pi\Key>
D:\SVN_Repository3\pi\Key>"C:\Program Files\Java\jdk1.7.0_67\bin\keytool.exe" -validity 3650 -genkeypair -v -alias client -keyalg RSA -storetype PKCS12 -keystore client.p12 -dname "CN=AndroidClient,OU=R&D,O=SDL,L=Taichung,ST=Taiwan,c=TW" -storepass client1234
針對 CN=AndroidClient, OU=R&D, O=SDL, L=Taichung, ST=Taiwan, C=TW 產生有效期 3,650 天的 2,048 位元 RSA 金鑰組以及自我簽署憑證 (SHA256withRSA)

[儲存 client.p12]

D:\SVN_Repository3\pi\Key>dir
 磁碟區 D 中的磁碟是 新增磁碟區
 磁碟區序號:  3AAA-91FF

 D:\SVN_Repository3\pi\Key 的目錄

2017/08/31  13:32    <DIR>          .
2017/08/31  13:32    <DIR>          ..
2017/08/31  13:32             2,572 client.p12
2017/08/31  13:27             2,228 server.keystore
               2 個檔案           4,800 位元組
               2 個目錄  679,286,403,072 位元組可用

D:\SVN_Repository3\pi\Key>
D:\SVN_Repository3\pi\Key>"C:\Program Files\Java\jdk1.7.0_67\bin\keytool.exe" -export -v -alias client -keystore client.p12 -storetype PKCS12 -storepass client1234 -rfc -file client.cer
憑證儲存在檔案 <client.cer>

D:\SVN_Repository3\pi\Key>dir
 磁碟區 D 中的磁碟是 新增磁碟區
 磁碟區序號:  3AAA-91FF

 D:\SVN_Repository3\pi\Key 的目錄

2017/08/31  13:56    <DIR>          .
2017/08/31  13:56    <DIR>          ..
2017/08/31  13:57             1,260 client.cer
2017/08/31  13:55             2,572 client.p12
2017/08/31  13:54             2,230 server.keystore
               3 個檔案           6,062 位元組
               2 個目錄  679,286,390,784 位元組可用

D:\SVN_Repository3\pi\Key>
D:\SVN_Repository3\pi\Key>"C:\Program Files\Java\jdk1.7.0_67\bin\keytool.exe" -export -v -alias server -keystore server.keystore -storepass store1234 -rfc -file server.cer
憑證儲存在檔案 <server.cer>

D:\SVN_Repository3\pi\Key>dir
 磁碟區 D 中的磁碟是 新增磁碟區
 磁碟區序號:  3AAA-91FF

 D:\SVN_Repository3\pi\Key 的目錄

2017/08/31  13:58    <DIR>          .
2017/08/31  13:58    <DIR>          ..
2017/08/31  13:57             1,260 client.cer
2017/08/31  13:55             2,572 client.p12
2017/08/31  13:58             1,260 server.cer
2017/08/31  13:54             2,230 server.keystore
               4 個檔案           7,322 位元組
               2 個目錄  679,286,386,688 位元組可用

D:\SVN_Repository3\pi\Key>
D:\SVN_Repository3\pi\Key>"C:\Program Files\Java\jdk1.7.0_67\bin\keytool.exe" -import -v -alias server -file server.cer -keystore client.truststore -storepass trust1234
擁有者: CN=AndroidServer, OU=R&D, O=SDL, L=Taichung, ST=Taiwan, C=TW
發出者: CN=AndroidServer, OU=R&D, O=SDL, L=Taichung, ST=Taiwan, C=TW
序號: 33fc9a74
有效期自: Thu Aug 31 13:54:47 CST 2017 到: Sun Aug 29 13:54:47 CST 2027
憑證指紋:
         MD5:  C7:7E:71:51:21:79:BF:BE:D9:42:E5:42:B7:0F:4D:19
         SHA1: DD:3E:87:9E:92:67:6D:F4:18:70:E8:23:82:93:A6:A9:9D:0A:7A:F4
         SHA256: 05:EE:F8:9F:DB:89:C2:D0:20:40:C5:77:DF:50:2D:3D:06:E4:FC:EE:15:4A:39:14:0E:F2:AF:29:23:65:A6:49
         簽章演算法名稱: SHA256withRSA
         版本: 3

擴充套件:

#1: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: CB 69 A6 E6 E4 06 5F 7C   EF 14 38 37 88 F8 30 A7  .i...._...87..0.
0010: 1A 7F 7F 3A                                        ...:
]
]

信任這個憑證? [否]:  y
憑證已新增至金鑰儲存庫中
[儲存 client.truststore]

D:\SVN_Repository3\pi\Key>dir
 磁碟區 D 中的磁碟是 新增磁碟區
 磁碟區序號:  3AAA-91FF

 D:\SVN_Repository3\pi\Key 的目錄

2017/08/31  14:02    <DIR>          .
2017/08/31  14:02    <DIR>          ..
2017/08/31  13:57             1,260 client.cer
2017/08/31  13:55             2,572 client.p12
2017/08/31  14:02               940 client.truststore
2017/08/31  13:58             1,260 server.cer
2017/08/31  13:54             2,230 server.keystore
               5 個檔案           8,262 位元組
               2 個目錄  679,286,382,592 位元組可用

D:\SVN_Repository3\pi\Key>
D:\SVN_Repository3\pi\Key>"C:\Program Files\Java\jdk1.7.0_67\bin\keytool.exe" -import -v -alias client -file client.cer -keystore server.keystore -storepass store1234
擁有者: CN=AndroidClient, OU=R&D, O=SDL, L=Taichung, ST=Taiwan, C=TW
發出者: CN=AndroidClient, OU=R&D, O=SDL, L=Taichung, ST=Taiwan, C=TW
序號: 4a2adb9c
有效期自: Thu Aug 31 13:55:07 CST 2017 到: Sun Aug 29 13:55:07 CST 2027
憑證指紋:
         MD5:  A6:8C:FA:94:8C:F9:D5:09:54:DD:12:FE:75:51:19:86
         SHA1: 10:7D:E3:DC:D8:42:43:FF:46:97:26:A2:8F:AA:B7:90:74:16:8D:24
         SHA256: 3B:30:95:09:AE:1A:AC:AC:2D:3C:10:4B:7B:33:4B:E6:5B:51:AC:C7:C8:A0:99:EF:39:0F:64:DE:F5:56:6E:D8
         簽章演算法名稱: SHA256withRSA
         版本: 3

擴充套件:

#1: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 32 BA E6 02 8E A5 3D 02   77 01 21 29 B0 55 21 82  2.....=.w.!).U!.
0010: F6 8B 34 9B                                        ..4.
]
]

信任這個憑證? [否]:  y
憑證已新增至金鑰儲存庫中
[儲存 server.keystore]

D:\SVN_Repository3\pi\Key>
D:\SVN_Repository3\pi\Key>dir
 磁碟區 D 中的磁碟是 新增磁碟區
 磁碟區序號:  3AAA-91FF

 D:\SVN_Repository3\pi\Key 的目錄

2017/08/31  14:02    <DIR>          .
2017/08/31  14:02    <DIR>          ..
2017/08/31  13:57             1,260 client.cer
2017/08/31  13:55             2,572 client.p12
2017/08/31  14:02               940 client.truststore
2017/08/31  13:58             1,260 server.cer
2017/08/31  14:04             3,138 server.keystore
               5 個檔案           9,170 位元組
               2 個目錄  679,286,382,592 位元組可用

D:\SVN_Repository3\pi\Key>
D:\SVN_Repository3\pi\Key>"C:\Program Files\Java\jdk1.7.0_67\bin\keytool.exe" -list -keystore server.keystore -storepass store1234

金鑰儲存庫類型: JKS
金鑰儲存庫提供者: SUN

您的金鑰儲存庫包含 2 項目

client, 2017/8/31, trustedCertEntry,
憑證指紋 (SHA1): 10:7D:E3:DC:D8:42:43:FF:46:97:26:A2:8F:AA:B7:90:74:16:8D:24
server, 2017/8/31, PrivateKeyEntry,
憑證指紋 (SHA1): DD:3E:87:9E:92:67:6D:F4:18:70:E8:23:82:93:A6:A9:9D:0A:7A:F4

D:\SVN_Repository3\pi\Key>
D:\SVN_Repository3\pi\Key>"C:\Program Files\Java\jdk1.7.0_67\bin\keytool.exe" -list -keystore client.truststore -storepass trust1234

金鑰儲存庫類型: JKS
金鑰儲存庫提供者: SUN

您的金鑰儲存庫包含 1 項目

server, 2017/8/31, trustedCertEntry,
憑證指紋 (SHA1): DD:3E:87:9E:92:67:6D:F4:18:70:E8:23:82:93:A6:A9:9D:0A:7A:F4

D:\SVN_Repository3\pi\Key>
D:\SVN_Repository3\pi\Key>"C:\Program Files\Java\jdk1.7.0_67\bin\keytool.exe" -import -v -alias server -file server.cer -keystore trust.bks -storepass trust1234 -storetype BKS -provider org.bouncycastle.jce.provider.BouncyCastleProvider
擁有者: CN=AndroidServer, OU=R&D, O=SDL, L=Taichung, ST=Taiwan, C=TW
發出者: CN=AndroidServer, OU=R&D, O=SDL, L=Taichung, ST=Taiwan, C=TW
序號: 33fc9a74
有效期自: Thu Aug 31 13:54:47 CST 2017 到: Sun Aug 29 13:54:47 CST 2027
憑證指紋:
         MD5:  C7:7E:71:51:21:79:BF:BE:D9:42:E5:42:B7:0F:4D:19
         SHA1: DD:3E:87:9E:92:67:6D:F4:18:70:E8:23:82:93:A6:A9:9D:0A:7A:F4
         SHA256: 05:EE:F8:9F:DB:89:C2:D0:20:40:C5:77:DF:50:2D:3D:06:E4:FC:EE:15:4A:39:14:0E:F2:AF:29:23:65:A6:49
         簽章演算法名稱: SHA256withRSA
         版本: 3

擴充套件:

#1: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: CB 69 A6 E6 E4 06 5F 7C   EF 14 38 37 88 F8 30 A7  .i...._...87..0.
0010: 1A 7F 7F 3A                                        ...:
]
]

信任這個憑證? [否]:  y
憑證已新增至金鑰儲存庫中
[儲存 trust.bks]

D:\SVN_Repository3\pi\Key>
D:\SVN_Repository3\pi\Key>dir
 磁碟區 D 中的磁碟是 新增磁碟區
 磁碟區序號:  3AAA-91FF

 D:\SVN_Repository3\pi\Key 的目錄

2017/09/01  09:44    <DIR>          .
2017/09/01  09:44    <DIR>          ..
2017/08/31  13:57             1,260 client.cer
2017/08/31  13:55             2,572 client.p12
2017/08/31  14:02               940 client.truststore
2017/08/31  13:58             1,260 server.cer
2017/08/31  14:04             3,138 server.keystore
2017/09/01  09:44               962 trust.bks
               6 個檔案          10,132 位元組
               2 個目錄  679,233,712,128 位元組可用

D:\SVN_Repository3\pi\Key>

//下載 Bouncy Castle
// https://www.bouncycastle.org/latest_releases.html
// 拷貝 bcprov-ext-jdk15on-158.jar 到 C:\Program Files\Java\jdk1.7.0_67\jre\lib\ext
// 拷貝 bcprov-ext-jdk15on-158.jar 到 C:\Program Files\Java\jre7\lib\ext
// 將下一行加入 C:\Program Files\Java\jre7\lib\security\java.security 和 C:\Program Files\Java\jdk1.7.0_67\jre\lib\security\java.security
// security.provider.11=org.bouncycastle.jce.provider.BouncyCastleProvider
// 新增 CLASSPATH=C:\Program Files\Java\jdk1.7.0_67\jre\lib\ext\bcprov-ext-jdk15on-158.jar
D:\SVN_Repository3\pi\Key>"C:\Program Files\Java\jdk1.7.0_67\bin\keytool.exe" -importkeystore -srckeystore client.p12 -srcstoretype PKCS12 -srcstorepass client1234 -destkeystore client.bks -deststoretype BKS -deststorepass client1234 -provider org.bouncycastle.jce.provider.BouncyCastleProvider
匯入別名 client 的項目時出現問題: java.security.KeyStoreException: java.io.IOException: Error initialising store of key store: java.security.InvalidKeyException: Illegal key size。
未匯入別名 client 的項目。
Do you want to quit the import process? [no]:  y
已完成匯入命令: 成功匯入 0 個項目,1 個項目失敗或已取消

D:\SVN_Repository3\pi\Key>
//下載 Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files 7 Download
//http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html
//解壓縮 UnlimitedJCEPolicyJDK7.zip
//到 C:\Program Files\Java\jdk1.7.0_67\jre\lib\security
//備份舊的 local_policy.jar, US_export_policy.jar
//拷貝新的 local_policy.jar, US_export_policy.jar
D:\SVN_Repository3\pi\Key>"C:\Program Files\Java\jdk1.7.0_67\bin\keytool.exe" -importkeystore -srckeystore client.p12 -srcstoretype PKCS12 -srcstorepass client1234 -destkeystore client.bks -deststoretype BKS -deststorepass client1234 -provider org.bouncycastle.jce.provider.BouncyCastleProvider
已成功匯入別名 client 的項目。
已完成匯入命令: 成功匯入 1 個項目,0 個項目失敗或已取消

D:\SVN_Repository3\pi\Key>dir
 磁碟區 D 中的磁碟是 新增磁碟區
 磁碟區序號:  3AAA-91FF

 D:\SVN_Repository3\pi\Key 的目錄

2017/09/01  10:26    <DIR>          .
2017/09/01  10:26    <DIR>          ..
2017/09/01  10:26             2,234 client.bks
2017/08/31  13:57             1,260 client.cer
2017/08/31  13:55             2,572 client.p12
2017/08/31  14:02               940 client.truststore
2017/08/31  13:58             1,260 server.cer
2017/08/31  14:04             3,138 server.keystore
2017/09/01  09:44               962 trust.bks
               7 個檔案          12,366 位元組
               2 個目錄  679,233,679,360 位元組可用

D:\SVN_Repository3\pi\Key>

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年4月17日 星期一

OpenSSL 證書

openssl学习笔记--CA及https网站证书配置

root@arduino:~/openssl# mkdir openssl
root@arduino:~/openssl# cd openssl
root@arduino:~/openssl# mkdir private
// 產生 根私鑰
root@arduino:~/openssl# openssl genrsa -out private/cakey.pem 2048
root@arduino:~/openssl# vi /etc/ssl/openssl.cnf
dir             = /root/openssl         # Where everything is kept
default_md = sha512 # 使用預設(sha1)方法,chrome 會報說此方法已經不安全,不給用
ountryName                     = Country Name (2 letter code)
countryName_default             = TW
stateOrProvinceName             = State or Province Name (full name)
stateOrProvinceName_default     = Taiwan
localityName                    = Locality Name (eg, city)
localityName_default            = Taichung
0.organizationName              = Organization Name (eg, company)
0.organizationName_default      = SDL
organizationalUnitName          = Organizational Unit Name (eg, section)
organizationalUnitName_default  = R&D

// 產生 根證書
root@arduino:~/openssl# openssl req -new -x509 -key private/cakey.pem -out cacert.pem -days 3650
root@arduino:~/openssl# touch index.txt serial
root@arduino:~/openssl# echo 01 >serial
root@arduino:~/openssl# mkdir newcerts
root@arduino:~/openssl# mkdir web1
// 產生網站要用的私鑰,通常在別台電腦
root@arduino:~/openssl# openssl genrsa -out web1/httpd.key 2048
root@arduinoYun:~/openssl# cp /etc/ssl/openssl.cnf web1/
root@arduinoYun:~/openssl# vi web/openssl.cnf
req_extensions = v3_req # The extensions to add to a certificate request
[ v3_req ]
subjectAltName = @alt_names
# Extensions to add to a certificate request
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
[alt_names]
IP.1 = 192.168.1.61
IP.2 = 192.168.240.1
IP.3 = 192.168.43.201
DNS.1 = arduinoyun.local

// 產生證書申請書
root@arduino:~/openssl# openssl req -new -key web1/httpd.key -out web1/httpd.csr -sha512 -config web1/openssl.cnf
// 填入要簽署的網址
Common Name (e.g. server FQDN or YOUR name) []:Arduino Yun
// 下面兩個不要填
A challenge password []:
An optional company name []:

// 可用下面命令,查看證書申請
root@arduinoYun:~/openssl# openssl req -text -noout -in web1/httpd.csr
// 將證書申請書送到根證書的機器,簽屬證書
root@arduino:~/openssl# openssl ca -in web1/httpd.csr -out web1/httpd.crt -days 3650 -extensions v3_req -extfile web1/openssl.cnf
// 回答兩個 y 即可,若發生下列錯誤,查詢 newcerts 目錄下最後的一個 pem
failed to update database
TXT_DB error number 2
// 使用命令
root@arduinoYun:~/openssl# openssl ca -revoke newcerts/02.pem

root@arduino:~/openssl# cd ..
root@arduino:~# vi pythonWeb.py
  server.socket = ssl.wrap_socket(server.socket,
    keyfile='openssl/web1/httpd.key',
    certfile='openssl/web1/httpd.crt',
    #cert_reqs=ssl.CERT_REQUIRED,
    #ca_certs='openssl/cacert.pem',
    server_side=True,
    ssl_version=ssl.PROTOCOL_TLSv1)

傳送根證書 cacert.pem 到 local, 並改名為 cacert.crt
匯入憑證