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

2024年11月19日 星期二

Linux 開發筆記 - OpenLDAP StartTLS 憑證驗證與故障排除 @ Ubuntu 20.04


負責 DevOps 同事休假,當初 LDAP 架設沒涉入,用 AI 輔助來練一下功,盡量讓同事好好休假不用 oncall 解題,就把這過程筆記一下。

現在有 AI 輔助服務,做事的心態變了不少,包括:
  1. 面對不是自己從頭到尾參與的計劃時,該怎樣建立自己了解系統思維或是達成想做的任務
  2. AI 的答案也不一定是對的,該如何驗證(如同管理或跨團隊合作上,請夥伴做事,但不一定做對,該怎樣驗正)
事件起因是一些小型內部服務,因 LDAP 憑證失效而無法完成登入(已登入不受影響),我的追法:
  1. 請 AI 給我指令或程式,檢驗快速檢驗 ldap 連線過程,著重在憑證檢查,例如檢查 https 憑證最常就是靠 openssl 指令或是 browser 瀏覽檢視憑證
  2. 有時 AI 會回的很搞剛,開始回寫 code 的 python 解法,這時因為自己有經驗 openssl 指令就能搞定,所以不斷提醒 AI 直接給指令解
  3. 對於 OpenLDAP 不熟的我,開始追問 AI 憑證相關的方向,才順勢了解 StartTLS ,才知道有 ldapsearch, slaptest 指令可用
  4. 對於管理線上服務踩過雷,知道不能隨便 service restart,多問一下 AI 該怎樣先檢驗設定檔,避免機器從 running -> stop -> 設定有誤 -> 服務停止營運
使用 openssl 指令檢查 SSL 憑證,假設網域是 ldap-dmz.changyy.org

```
$ openssl s_client -connect ldap-dmz.changyy.org:443 
...
---
SSL handshake has read xxxx bytes and written xxx bytes
Verification: OK
---
...
```

使用 openssl 指令檢查 LDAP + StartTLS 憑證,假設網域是 ldap-dmz.changyy.org

```
$ openssl s_client -connect ldap-dmz.changyy.org:389 -starttls ldap
...
---
SSL handshake has read xxxx bytes and written xxx bytes
Verification error: certificate has expired
---
...
```

得知 LDAP + StartTLS 使用流程中的憑證過期了,且此例剛好 https 憑證已正常工作,僅 LDAP + StartTLS 的部分失敗,所以很輕鬆的可以把 https 憑證複製一份到 ldap 使用即可。先追蹤設定檔位置:

```
$ sudo cat /etc/ldap/slapd.d/cn\=config.ldif | grep -i TLS
olcTLSCACertificateFile: /etc/ssl/ldap/wildcard.*.ca-bundle
olcTLSCertificateFile: /etc/ssl/ldap/wildcard.*.crt
olcTLSCertificateKeyFile: /etc/ssl/ldap/wildcard.*.key
$ sudo tree -L 1 /etc/ssl/
/etc/ssl/
├── certs
├── ldap
├── nginx
├── openssl.cnf
└── private
```

速速解:

```
$ sudo cp -r /etc/ssl/ldap /etc/ssl/ldap-bak
$ sudo cp /etc/ssl/nginx/wildcard.* /etc/ssl/ldap/
```

檢驗設定檔和重啟服務:

```
$ sudo slaptest
config file testing succeeded
$ sudo service slapd restart
```

再次驗證:

```
$ openssl s_client -connect ldap-dmz.changyy.org:389 -starttls ldap
...
---
SSL handshake has read xxxx bytes and written xxx bytes
Verification: OK
---
...
```

此外,追蹤 LDAP 和使用他的服務時,意外發現不同的服務整合過程,也順手筆記一下,例如 Apache2 設定檔:

僅 LDAP 非加密:

<Location />
    Order allow,deny
    Allow from all
    AuthType basic
    AuthName "service.changyy.org"
    AuthBasicProvider ldap
    AuthLDAPUrl "ldap://ldap-dmz.changyy.org/dc=changyy,dc=org?uid"
    Require valid-user
</Location>

LDAP + StartTLS:

<Location />
    Order allow,deny
    Allow from all
    AuthType basic
    AuthName "service.changyy.org"
    AuthBasicProvider ldap
    AuthLDAPUrl "ldap://ldap-dmz.changyy.org/dc=changyy,dc=org?uid" TLS
    Require valid-user
</Location>

對應的其他服務也會有類似架構,舉例來說 Mantis 也有 mantisbt.org/docs/master/en-US/Admin_Guide/html/admin.config.auth.ldap.html

預設是啟用 LDAP + StartTLS

//
// Determines whether the connection will attempt an opportunistic upgrade to a TLS connection (STARTTLS).
//
// Defaults to ON.
//
// $g_ldap_use_starttls = ON

需要測試 LDAP 健康情況時,可以把它關閉

// $g_ldap_use_starttls = OFF

補充檢查 ldap service 健康情況時,最常是直接使用 ldapsearch 指令:

```
$ sudo apt install ldap-utils
$ ldapsearch -x -H 'ldap://ldap-dmz.changyy.org' -b 'dc=changyy,dc=org'
...
# search result
search: #
result: 0 Success
...
# numResponses: ###
# numEntries: ###
```

測試 LDAP + StartTLS:

```
$ ldapsearch -x -H 'ldap://ldap-dmz.changyy.org' -b 'dc=changyy,dc=org' -Z
...
ldap_start_tls: Connect error (-11)
additional info: (unknown error code)
ldap_result: Can't contact LDAP server (-1)
```

測試 LDAP + StartTLS 需要更多 debug 資訊:

```
$ ldapsearch -x -H 'ldap://ldap-dmz.changyy.org' -b 'dc=changyy,dc=org' -Z -d 1
...
TLS: peer cert untrusted or revoked (0x402)
TLS: can't connect: (unknown error code).
...
ldap_start_tls: Connect error (-11)
...
```

用 PHP Code 嘗試建立連線,先確認 php.ini 套件:

```
php -i | grep ldap
/etc/php/7.4/cli/conf.d/20-ldap.ini,
Protocols => dict, file, ftp, ftps, gopher, http, https, imap, imaps, ldap, ldaps, pop3, pop3s, rtmp, rtsp, scp, sftp, smb, smbs, smtp, smtps, telnet, tftp
ldap
...
```

運行:

```
$ cat /tmp/t.php 
<?php
$ldapconn = ldap_connect("ldap://ldap-dmz.changyy.org");
if ($ldapconn) {
    ldap_set_option($ldapconn, LDAP_OPT_PROTOCOL_VERSION, 3);
    ldap_set_option($ldapconn, LDAP_OPT_REFERRALS, 0);
    // 關閉 TLS
    putenv('LDAPTLS_REQCERT=never');
    
    $bind = ldap_bind($ldapconn);
    if ($bind) {
        echo "LDAP bind successful...\n";
    } else {
        echo "LDAP bind failed...\n";
    }
}
$ php /tmp/t.php 
LDAP bind successful...
```

收工!

2024年2月16日 星期五

Docker 開發筆記 - 使用 Docker Compose 架設 Gitlab 服務 / 處理自訂 Ports / HTTPS SSL 憑證 @ macOS 14.2.1




延續上一篇 Docker 開發筆記 - 使用 Docker Compose 架設 Jenkins 服務 @ macOS 14.2.1 活動,該寫一下 gitlab 架設筆記。其實過年期間有播空試試,但是處理很不順,再加上跑去玩樂就荒廢了。昨晚終於可以收尾一下,把一些使用過程列一下。當時踩坑的原因是自己沒有把環境清乾淨,花了大把時間除錯。

先來個環境簡介:

% docker version 

Client:

 Cloud integration: v1.0.35+desktop.10

 Version:           25.0.3

 API version:       1.44

 Go version:        go1.21.6

 Git commit:        4debf41

 Built:             Tue Feb  6 21:13:26 2024

 OS/Arch:           darwin/arm64

 Context:           desktop-linux


Server: Docker Desktop 4.27.2 (137060)

 Engine:

  Version:          25.0.3

  API version:      1.44 (minimum version 1.24)

  Go version:       go1.21.6

  Git commit:       f417435

  Built:            Tue Feb  6 21:14:22 2024

  OS/Arch:          linux/arm64

  Experimental:     false

 containerd:

  Version:          1.6.28

  GitCommit:        ae07eda36dd25f8a1b98dfbf587313b99c0190bb

 runc:

  Version:          1.1.12

  GitCommit:        v1.1.12-0-g51d5e94

 docker-init:

  Version:          0.19.0

  GitCommit:        de40ad0


清乾淨後再重啟:

% docker-compose down -v
% rm -rf ~/docker-gitlab
% docker-compose up

總之先來為回顧官網的 docker 教學吧!依照 gitlab 官網的安裝簡介 可以很快速地裝起來 :

% cat /etc/hosts | grep gitlab
127.0.0.1 gitlab.example.com
% cat docker-compose.yml 
# https://docs.docker.com/compose/compose-file/compose-versioning/
version: '3.8' 
services:
  gitlab:
    image: gitlab/gitlab-ee:latest
    container_name: gitlab
    restart: always
    hostname: 'gitlab.example.com'
    environment:
      GITLAB_OMNIBUS_CONFIG: |
        external_url 'http://gitlab.example.com:8929'
        gitlab_rails['gitlab_shell_ssh_port'] = 2424
    ports:
      - '8929:8929'
      - '2424:2424'
    volumes:
      - '~/docker-gitlab/config:/etc/gitlab'
      - '~/docker-gitlab/logs:/var/log/gitlab'
      - '~/docker-gitlab/data:/var/opt/gitlab'
    shm_size: '256m'

% docker-compose up
...

% docker container ls                   
CONTAINER ID   IMAGE                     COMMAND             CREATED         STATUS                   PORTS                                                             NAMES
XXXXXXXXXXXX   gitlab/gitlab-ee:latest   "/assets/wrapper"   3 minutes ago   Up 3 minutes (healthy)   22/tcp, 443/tcp, 0.0.0.0:20080->80/tcp, 0.0.0.0:20022->2424/tcp   gitlab

主要是看到 docker container 狀態要顯示 healthy ,接著就可以去瀏覽 http://gitlab.example.com:8929 位置了(註:gitlab.example.com被我設定成 127.0.0.1)。

接著我還在惡搞切換 nginx port,以及碰到 chrome browser 的 ERR_UNSAFE_PORT,最後延宕了好一陣子 :P 就把剩下的流水帳心得都記錄一下:
  • 關於 gitlab/gitlab-ee:latest 和 gitlab/gitlab-ce:latest ,據說 gitlab/gitlab-ee:latest 沒有序號啟動時,就等同於 gitlab/gitlab-ce:latest ,就統一用 gitlab/gitlab-ee:latest 即可
  • 記得初次使用時,登入帳號是 root ,密碼躲在 /etc/gitlab/initial_root_password
% docker container ls
CONTAINER ID   IMAGE                     COMMAND             CREATED          STATUS                    PORTS                                                              NAMES
XXXXXXXX   gitlab/gitlab-ee:latest   "/assets/wrapper"   20 minutes ago   Up 18 minutes (healthy)   80/tcp, 443/tcp, 0.0.0.0:20443->20443/tcp, 0.0.0.0:20022->22/tcp   gitlab

% docker exec -it XXXXXXXX cat /etc/gitlab/initial_root_password
# WARNING: This value is valid only in the following conditions
#          1. If provided manually (either via `GITLAB_ROOT_PASSWORD` environment variable or via `gitlab_rails['initial_root_password']` setting in `gitlab.rb`, it was provided before database was seeded for the first time (usually, the first reconfigure run).
#          2. Password hasn't been changed manually, either via UI or via command line.
#
#          If the password shown here doesn't work, you must reset the admin password following https://docs.gitlab.com/ee/security/reset_user_password.html#reset-your-root-password.

Password: yNRnhTRu9IZ/eBvlC3BCDeuK6zn6BUBmGB+a89SMpn0=

# NOTE: This file will be automatically deleted in the first reconfigure run after 24 hours.
  • 使用 GITLAB_OMNIBUS_CONFIG 可以便利的完成絕大部分的設定
  • 自訂的 port 請避開 chrome browser 定義的 ERR_UNSAFE_PORT 清單,這個雷不小心會耗掉非常多時間的,例如我偷懶把 80 增加個 10000 變成 10080 ...就中招,讓我以為有什麼服務沒啟動成功
  • 善用 external_url 設定外部連進去的資訊,並且把 HOST:CONTAINER Ports 都填寫一樣是最輕鬆的方式:
    environment:
      GITLAB_OMNIBUS_CONFIG: |
        external_url 'http://gitlab.example.com:20080'
        gitlab_rails['gitlab_shell_ssh_port'] = 20022
    ports:
      - '20080:20080'
      - '20022:20022'
  • 想要來惡搞讓 nginx 聽在不同 port ,那就要設定更多東西
    environment:
      GITLAB_OMNIBUS_CONFIG: |
        external_url 'http://gitlab.example.com:20080'
        nginx['listen_port'] = 80
        gitlab_rails['gitlab_shell_ssh_port'] = 22
    ports:
      - '20080:80'
      - '20022:22'
  • 想要啟用加密連線,單靠 external_url 更新成 `https://` 的描述也會默認啟動 SSL 加密連線服務,但下一刻還得處理憑證問題,連續動作:
% mkdir -p ssl
% test -e ./ssl/localhost.key || openssl genpkey -algorithm RSA -out ./ssl/localhost.key
% test -e ./ssl/localhost.crt || openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout ./ssl/localhost.key -out ./ssl/localhost.crt -subj '/C=US/ST=State/L=City/O=Organization/OU=Unit/CN=localhost'
% tree ssl 
ssl
├── localhost.crt
└── localhost.key

1 directory, 2 files 
 
% cat docker-compose.yml
 ...
     environment:
       GITLAB_OMNIBUS_CONFIG: |
         external_url 'https://gitlab.example.com:20443'
         #nginx['listen_port'] = 443
         nginx['ssl_certificate'] = "/etc/gitlab-ssl-usage/localhost.crt"
         nginx['ssl_certificate_key'] = "/etc/gitlab-ssl-usage/localhost.key"
         gitlab_rails['gitlab_shell_ssh_port'] = 22

     ports:
       - '20443:20443'
       - '20022:22'

     volumes:
       - './ssl:/etc/gitlab-ssl-usage'
  • 若不想靠 volumes 掛進來,也可以改用 command 來發動
     command: ["sh", "-c", "mkdir -p /etc/gitlab-ssl-usage && (test -e /etc/gitlab-ssl-usage/localhost.key || openssl genpkey -algorithm RSA -out /etc/gitlab-ssl-usage/localhost.key ) && ( test -e /etc/gitlab-ssl-usage/localhost.crt || openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/gitlab-ssl-usage/localhost.key -out /etc/gitlab-ssl-usage/localhost.crt -subj '/C=US/ST=State/L=City/O=Organization/OU=Unit/CN=localhost' ) && /assets/wrapper "]
     #command: ["sh", "-c", "/tmp/config/setup.sh"]
     environment:
       GITLAB_OMNIBUS_CONFIG: |
         external_url 'https://gitlab.example.com:20443'
         nginx['ssl_certificate'] = "/etc/gitlab-ssl-usage/localhost.crt"
         nginx['ssl_certificate_key'] = "/etc/gitlab-ssl-usage/localhost.key"
         gitlab_rails['gitlab_shell_ssh_port'] = 22

     ports:
       - '20443:20443'
       - '20022:22'

  • 最初實驗時還曾碰過 redis 跟 postgres 無法跑起來的問題 ( /var/opt/gitlab/postgresql/ , /var/opt/gitlab/redis/ ),以至於變成非常臭長的架構,我想沒事都可以不用這樣惡搞了,在此順便留戀一下

# https://docs.docker.com/compose/compose-file/compose-versioning/
version: '3.8' 
services:
  redis:
    restart: unless-stopped 
    image: redis:latest
    container_name: gitlab-redis
    volumes:
      - ~/docker_gitlab_home/redis:/data
      - ~/docker_gitlab_home/socket-redis:/var/run/redis
  postgres:
    image: postgres:latest
    container_name: gitlab-postgres
    restart: unless-stopped
    environment:
      POSTGRES_USER: gitlab
      POSTGRES_PASSWORD: gitlabAdmin
    volumes:
      - ~/docker_gitlab_home/postgres:/var/lib/postgresql/data
      - ~/docker_gitlab_home/socket-postgresql:/var/run/postgresql
  gitlab:
    # https://docs.gitlab.com/ee/install/docker.html#install-gitlab-using-docker-compose
    # https://hub.docker.com/r/gitlab/gitlab-ee/
    # https://hub.docker.com/r/gitlab/gitlab-ce
    image: gitlab/gitlab-ee:latest
    container_name: gitlab-main
    depends_on:
      - postgres
      - redis
    # https://docs.docker.com/config/containers/start-containers-automatically/#use-a-restart-policy
    restart: unless-stopped 
    hostname: 'localhost'
    command: ["sh", "-c", "mkdir -p /etc/gitlab-ssl-usage && (test -e /etc/gitlab-ssl-usage/localhost.key || openssl genpkey -algorithm RSA -out /etc/gitlab-ssl-usage/localhost.key ) && ( test -e /etc/gitlab-ssl-usage/localhost.crt || openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/gitlab-ssl-usage/localhost.key -out /etc/gitlab-ssl-usage/localhost.crt -subj '/C=US/ST=State/L=City/O=Organization/OU=Unit/CN=localhost' ) && /assets/wrapper "]
    environment:
      GITLAB_OMNIBUS_CONFIG: |
        # Add any other gitlab.rb configuration here, each on its own line
        #external_url 'http://localhost:20080'
        #nginx['listen_port'] = 80
        external_url 'https://localhost:20443'
        gitlab_rails['gitlab_shell_ssh_port'] = 22
        nginx['listen_port'] = 443
        nginx['listen_https'] = true
        nginx['ssl_certificate'] = "/etc/gitlab-ssl-usage/localhost.crt"
        nginx['ssl_certificate_key'] = "/etc/gitlab-ssl-usage/localhost.key"
        #letsencrypt['enable'] = false
        gitlab_rails['db_username'] = "gitlab"
        gitlab_rails['db_password'] = "gitlabAdmin"
    ports:
      # note: ERR_UNSAFE_PORT - https://chromium.googlesource.com/chromium/src.git/+/refs/heads/main/net/base/port_util.cc#27
      # HOST:CONTAINER
      - 20443:443
      #- 20080:80
      - 20022:22
    volumes:
      - ~/docker_gitlab_home/config:/etc/gitlab
      - ~/docker_gitlab_home/logs:/var/log/gitlab
      - ~/docker_gitlab_home/data:/var/opt/gitlab
      - ~/docker_gitlab_home/redis:/var/opt/gitlab/data/redis
      - ~/docker_gitlab_home/postgresql:/var/opt/gitlab/postgresql
      - ~/docker_gitlab_home/socket-postgresql:/var/opt/gitlab/postgresql/
      - ~/docker_gitlab_home/socket-redis:/var/opt/gitlab/redis/ 

2023年9月26日 星期二

[Linux] OpenSSL AES-128 加解密 @ macOS 13.2.1, OpenSSL 3.1.2 1 Aug 2023

總覺得我是不是以前也寫過這類筆記? 查了下快十年前 XD 用的是 openssl des3 

由於工作中太常接觸 AES-128 加解密了,想要筆記一下方便未來查詢,而透過 openssl command 也方便交叉驗證程式是否正確,這次就仿 openssl des3 筆記:

明文:

% cat /tmp/input.txt
Hello World
% md5 /tmp/input.txt
MD5 (/tmp/input.txt) = e59ff97941044f85df5297e1c302d260
% hexdump /tmp/input.txt 
0000000 6548 6c6c 206f 6f57 6c72 0a64          
000000c

產生加解密的 Key 值:

% dd if=/dev/urandom of=/tmp/password bs=1 count=32
32+0 records in
32+0 records out
32 bytes transferred in 0.000303 secs (105611 bytes/sec)
% md5 /tmp/password 
MD5 (/tmp/password) = 92eeb8e1bec70865650e1f96e5cd1819
% hexdump /tmp/password 
0000000 cf23 5006 70d0 bf1e 0e9e a70c 10f0 ecd6
0000010 dc01 e156 d818 bff2 2e3e f859 28c9 a91d
0000020
% hexdump -v -e '/1 "%02x"' -n 16 /tmp/password 
23cf0650d0701ebf9e0e0ca7f010d6ec

產生加解密的 IV 值(其實同 Key 值產生即可,目前改用另一招):

% date | md5
5d6476c85eca3ec56fda4913f5578b83

使用 OpenSSL AES-128 加密:

% openssl enc -e -aes-128-cbc -in /tmp/input.txt -out /tmp/encrypt.txt -K 23cf0650d0701ebf9e0e0ca7f010d6ec -iv 5d6476c85eca3ec56fda4913f5578b83
% hexdump /tmp/encrypt.txt
0000000 c3d4 cb0a d845 182c 319e afdf b29c c484
0000010

使用 OpenSSL AES-128 解密:

% openssl enc -d -aes-128-cbc -in /tmp/encrypt.txt -out /tmp/output.txt -K 23cf0650d0701ebf9e0e0ca7f010d6ec -iv 5d6476c85eca3ec56fda4913f5578b83
% md5 /tmp/output.txt 
MD5 (/tmp/output.txt) = e59ff97941044f85df5297e1c302d260
% cat /tmp/output.txt 
Hello World

工作上很容易 Key 值是一個 32 bytes 的 binary 檔案,且不加入輸出至檔案的方式,可以立即看解密的內容,連續動作如下:

% openssl enc -d -aes-128-cbc -in /tmp/encrypt.txt -K $(hexdump -v -e '/1 "%02x"' -n 16 /tmp/password) -iv 5d6476c85eca3ec56fda4913f5578b83
Hello World

收工

2021年6月4日 星期五

[Linux] 升級 Red Hat Enterprise Server 的 OpenSSL, OpenSSH 服務 @ Red Hat Enterprise Linux Server release 5.3

這是一台滿舊的機器,大概 10 年前吧。同事想要 git clone 時,出現了失敗問題,追蹤一下是機器的 openssl 過舊,由於機器有他的任務在,不好意思亂更新系統資源,怕爆!所以採用 tarball 的安裝方式。

openssl 太舊時,連用 wget/curl 去下載 https 來源時都會失敗的,只好靠 http 或是 scp 搬東西進去。

$ lsb_release -a
Distributor ID: RedHatEnterpriseServer
Description: Red Hat Enterprise Linux Server release 5.3 (Tikanga)
Release: 5.3
Codename: Tikanga

$ openssl version
OpenSSL 0.9.8e-fips-rhel5 01 Jul 2008

只好挑個 /opt/tarball 安裝啦,沒想到要編譯 openssl 又會碰到 perl 版本不夠新:

$ wget http://www.cpan.org/src/5.0/perl-5.10.0.tar.gz
$ cd ~/perl-5.10.0
$ ./configure.gnu --prefix=/opt/tarball
$ make -j4 install

接著再安裝個 zlib ,採用 static 方式方便後續大家使用:

$ wget http://zlib.net/zlib-1.2.11.tar.gz
$ cd ~/zlib-1.2.11
$ ./configure --prefix=/opt/tarball --static
$ make install

編譯 openssl:

$ wget http://www.openssl.org/source/openssl-1.1.1k.tar.gz 
$ cd ~/openssl-OpenSSL_1_1_1k 
$ PATH=/opt/tarball/bin:$PATH ./config --prefix=/opt/tarball
$ make -j4 install

編譯 openssh 工具包:https://github.com/openssh/openssh-portable/releases

$ cd ~/openssh-portable-V_8_6_P1
$ autoreconf
$ LD_LIBRARY_PATH=/opt/tarball/lib:$LD_LIBRARY_PATH ./configure --prefix=/opt/tarball/ --with-ssl-dir=/opt/tarball
$ LD_LIBRARY_PATH=/opt/tarball/lib:$LD_LIBRARY_PATH make -j4 install
$ file /opt/tarball/bin/ssh
/opt/tarball/bin/ssh: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), for GNU/Linux 2.6.9, stripped

接著偷懶拉 code 方式:

$ GIT_SSH_COMMAND="LD_LIBRARY_PATH=/opt/tarball/lib:$LD_LIBRARY_PATH /opt/tarball/bin/ssh" git clone ...

或是在環境變數添加好:

LD_LIBRARY_PATH=/opt/tarball/lib:$LD_LIBRARY_PATH 
PATH=/opt/tarball/bin:$PATH

搞定!

2019年9月11日 星期三

[macOS] 修正 Python 錯誤訊息 (caused by URLError(SSLError(1, u'[SSL: TLSV1_ALERT_PROTOCOL_VERSION] tlsv1 alert protocol version (_ssl.c:590)'),))

查了一下,就是 openssl 版本不夠新。一開始還以為是自己用 MacPorts 維護,導致不是用系統 Python 的關係,但在追細一點就可以知道單純更新 openssl 就搞定了。

$ python -V
Python 2.7.16
$ /usr/bin/python -V
Python 2.7.10
$ /usr/bin/python -c "import json, urllib2; print json.load(urllib2.urlopen('https://www.howsmyssl.com/a/check'))['tls_version']"
TLS 1.2
$ python -c "import json, urllib2; print json.load(urllib2.urlopen('https://www.howsmyssl.com/a/check'))['tls_version']"
TLS 1.2

$ openssl version -a
OpenSSL 1.0.2s  28 May 2019
built on: reproducible build, date unspecified
platform: darwin64-x86_64-cc
options:  bn(64,64) rc4(ptr,int) des(idx,cisc,16,int) idea(int) blowfish(idx)
compiler: /usr/bin/clang -I. -I.. -I../include  -fPIC -fno-common -DOPENSSL_PIC -DZLIB -DOPENSSL_THREADS -D_REENTRANT -DDSO_DLFCN -DHAVE_DLFCN_H -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk -arch x86_64 -O3 -DL_ENDIAN -Wall -DOPENSSL_IA32_SSE2 -DOPENSSL_BN_ASM_MONT -DOPENSSL_BN_ASM_MONT5 -DOPENSSL_BN_ASM_GF2m -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM -DMD5_ASM -DAES_ASM -DVPAES_ASM -DBSAES_ASM -DWHIRLPOOL_ASM -DGHASH_ASM -DECP_NISTZ256_ASM
OPENSSLDIR: "/opt/local/etc/openssl"


就好好把 openssl 更新即可修正。感謝佛心 www.howsmyssl.com 測試服務:https://www.howsmyssl.com/

另外也可以直接拿 openssl 上場問問 Google server:

$ openssl s_client -connect google.com:443 -tls1_2

若自己的 openssl 不支援 TLS 1.2 時,會直接回應 unknown option -tls1_2

2019年7月24日 星期三

[C] 透過 CMAKE 搜尋 OpenSSL 函式庫產出 MD5 資料

最近幫同事 debug embedded linux 問題,恰好需要用 MD5 來做 hash ,隨意找找就用 OpenSSL 函式庫就對了。再加上原先寫的小程式已經靠 CMAKE 維護了,就繼續整合使用

CMakeLists.txt:

$ cat CMakeLists.txt
cmake_minimum_required(VERSION 3.11)
project (MD5)

SET(SOURCE_DIR ${CMAKE_SOURCE_DIR}/src)

# macOS
# $ mkdir b ; cd b;
# $ cmake .. -DOPENSSL_ROOT_DIR=/usr/local/opt/openssl -DOPENSSL_LIBRARIES=/usr/local/opt/openssl/lib
#
find_package(OpenSSL REQUIRED)
include_directories(${OPENSSL_INCLUDE_DIR})

ADD_EXECUTABLE(main
${SOURCE_DIR}/main.c
)
TARGET_LINK_LIBRARIES(main OpenSSL::SSL)


程式碼:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <openssl/md5.h>

const char * get_md5_string(const unsigned char *in, char *output) {
int i;
for(i = 0 ; i < MD5_DIGEST_LENGTH ; i++) {
sprintf(output + (i)*2, "%02x", in[i]);
}
output[MD5_DIGEST_LENGTH*2] = '\0';
return output;
}

int main(int argc, char *argv[]) {
unsigned char digest[MD5_DIGEST_LENGTH];
char readable_digest[MD5_DIGEST_LENGTH*2 + 1];

char *test = "HelloWorld";
char *input;

if (argc > 1)
input = argv[1];
else
input = test;

MD5_CTX context;
MD5_Init(&context);
MD5_Update(&context, input, strlen(input));
MD5_Final(digest, &context);

get_md5_string(digest, readable_digest);

printf("MD5: [%s]\n", readable_digest);

return 0;
}


編譯跟運行:

$ mkdir b
$ cd b ; çmake ..
$ make
$ ./main HelloWorld
MD5: [68e109f0f40ca72a15e05cc22786f8e6]
$ echo -ne "HelloWorld" | md5
68e109f0f40ca72a15e05cc22786f8e6

2015年2月9日 星期一

使用 Openssl / C++ Crypto++ (Cryptopp) 進行 AES-128 / AES-256 Encryption @ Ubutnu 14.04

去年在一些服務上有用到 AES Encryption,當時是用 PHP 處理的 :P 最近想說 openssl 很威,練一下好了 XD 然而 AES 有很多模式 Orz 直接用 openssl -h 就可以觀看

$ openssl -h
aes-128-cbc       aes-128-ecb       aes-192-cbc       aes-192-ecb    
aes-256-cbc       aes-256-ecb       base64            bf              
bf-cbc            bf-cfb            bf-ecb            bf-ofb          
camellia-128-cbc  camellia-128-ecb  camellia-192-cbc  camellia-192-ecb
camellia-256-cbc  camellia-256-ecb  cast              cast-cbc        
cast5-cbc         cast5-cfb         cast5-ecb         cast5-ofb      
des               des-cbc           des-cfb           des-ecb        
des-ede           des-ede-cbc       des-ede-cfb       des-ede-ofb    
des-ede3          des-ede3-cbc      des-ede3-cfb      des-ede3-ofb    
des-ofb           des3              desx              idea            
idea-cbc          idea-cfb          idea-ecb          idea-ofb        
rc2               rc2-40-cbc        rc2-64-cbc        rc2-cbc        
rc2-cfb           rc2-ecb           rc2-ofb           rc4            
rc4-40            seed              seed-cbc          seed-cfb        
seed-ecb          seed-ofb          zlib


一開始還真不知要挑個 :P 並且用 openssl 加密出來,在其他程式語言卻解不出來 Orz

$ echo -n "Hello World" | openssl aes-128-cbc -e -k "password" -out /tmp/output
$ openssl aes-128-cbc -d -k "password" -in /tmp/output
Hello World


後來才找到這篇文章:
openssl: recover key and IV by passphrase
http://security.stackexchange.com/questions/29106/openssl-recover-key-and-iv-by-passphrase,講得非常清楚,簡言之:

The encryption format used by OpenSSL is non-standard: it is "what OpenSSL does", and if all versions of OpenSSL tend to agree with each other, there is still no reference document which describes this format except OpenSSL source code.

例如加上 -P 可以印出細部訊息:

$ openssl aes-128-cbc -e -k "password" -P
salt=EDC6E641C29F08F0
key=2CBD7689AEB5880E13803871A1DCDDD5
iv =FFFFBF58B814E180882029109B437D74


每次執行 salt, key 和 iv 都會一直變動,所以,若要用 Openssl 驗證時,需要一口氣填好 key 跟 iv 資訊:

$ openssl aes-128-cbc -e -K '' -iv '' -P
salt=0100000000000000
key=00000000000000000000000000000000
iv =00000000000000000000000000000000


當指定 -K 跟 -iv 時,就不會出現亂跳的情況,同理,在其他程式語言(此例以 C++ 為例),就能夠順利加解密。別忘了 -K 跟 -iv 需要 HEX String 格式的參數,在 Unix-like 系統可以透過 echo, od 跟 sed 來辦事:

$ echo -n "0123456789012345" | od -A n -t x1 | sed 's/ //g'
30313233343536373839303132333435
$ openssl aes-128-cbc -e -K `echo -n "0123456789012345" | od -A n -t x1 | sed 's/ //g'` -iv '' -P
salt=0100000000000000
key=30313233343536373839303132333435
iv =00000000000000000000000000000000


別忘了,若是要用 AES-256 時,Key 要記得手動接好 XD

$  echo -n "01234567890123456789012345678901" | od -A n -t x1 | sed 's/ //g'
30313233343536373839303132333435
36373839303132333435363738393031

$ openssl aes-256-cbc -e -K 3031323334353637383930313233343536373839303132333435363738393031 -iv '' -P
salt=0100000000000000
key=3031323334353637383930313233343536373839303132333435363738393031
iv =00000000000000000000000000000000


接著,來寫一點 C++ 吧:

#include <iostream>
#include <fstream>
#include <cryptopp/aes.h>
#include <cryptopp/modes.h>
#include <cryptopp/filters.h>
// http://www.cryptopp.com/
// sudo apt-get install libcrypto++-dev
// $ g++ main.cpp -lcryptopp

int main(int argc, char **argv) {
        byte key[ CryptoPP::AES::DEFAULT_KEYLENGTH ], iv[ CryptoPP::AES::BLOCKSIZE ];
        memset( key, 0x00, CryptoPP::AES::DEFAULT_KEYLENGTH );
        memset( iv, 0x00, CryptoPP::AES::BLOCKSIZE );

        for (int i=0 ; i<CryptoPP::AES::DEFAULT_KEYLENGTH ; ++i)
                key[i] = ('0' + (i%10) ) ;

        std::cout << "block size: " << CryptoPP::AES::BLOCKSIZE << std::endl;
        std::cout << "key(" << CryptoPP::AES::DEFAULT_KEYLENGTH << "):[" << key << "]" << std::endl;

        std::string plaintext = "Hello world. To man to be a better man.";
        std::string ciphertext;

        // enc
        CryptoPP::AES::Encryption aesEncryption(key, CryptoPP::AES::DEFAULT_KEYLENGTH);
        CryptoPP::CBC_Mode_ExternalCipher::Encryption cbcEncryption( aesEncryption, iv );
        CryptoPP::StreamTransformationFilter stfEncryptor(cbcEncryption, new CryptoPP::StringSink( ciphertext ) );
        stfEncryptor.Put( reinterpret_cast<const unsigned char*>( plaintext.c_str() ), plaintext.length());
        stfEncryptor.MessageEnd();

        std::ofstream output ("/tmp/output");
        output << ciphertext ;
        output.close();

        // dec
        std::string decryptedtext;
        CryptoPP::AES::Decryption aesDecryption(key, CryptoPP::AES::DEFAULT_KEYLENGTH);
        CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption( aesDecryption, iv );
        CryptoPP::StreamTransformationFilter stfDecryptor(cbcDecryption, new CryptoPP::StringSink( decryptedtext ) );
        stfDecryptor.Put( reinterpret_cast<const unsigned char*>( ciphertext.c_str() ), ciphertext.size() );
        stfDecryptor.MessageEnd();

        std::cout << "dec: [" << decryptedtext << "]" << std::endl;

        return 0;
}


執行完的產出在 /tmp/output,可以再用 openssl 把它解回來,而上述範例的 Key 長度為 16 ,因此適用於 aes-128-CBC,若想要用 aes-256-cbc 僅需把 Key 的長度調整為 32 即可搞定 :P

$ g++ t.cpp -lcryptopp
$ ./a.out
block size: 16
key(16):[0123456789012345]
dec: [Hello world. To man to be a better man.]
$ openssl aes-128-cbc -d -K `echo -n '0123456789012345' | od -A n -t x1 | sed 's/ //g'` -iv '' -in /tmp/output
Hello world. To man to be a better man.

2014年9月18日 星期四

iOS 開發筆記 - 驗證 Apple Push Notification PEM File 以及 Remove PEM Password

半年前曾開發過: 使用 Apple Push Notification service (APNs),最近更新 PEM  後,要驗證一下 PEM 是否正確。

驗證還滿簡單的,單純用 openssl 進行,假設是 dev 模式,對象就是 snadbox:

$ openssl s_client -connect gateway.sandbox.push.apple.com:2195 -cert cert.pem -key key.pem

其中 cert.pem 跟 key.pem 也可以合在一起:

$ cat cert.pem key.pem > out.pem
$ openssl s_client -connect gateway.sandbox.push.apple.com:2195 -cert out.pem


假設產出的 key.pem 有密碼保護,為了圖方便想要去密碼的話,可以用:

$ openssl rsa -in key.pem -out nopass.pem

如此一來就搞定了,若測試的是 Production PEM ,記得改用 gateway.push.apple.com:2195 即可。

$ openssl s_client -connect gateway.push.apple.com:2195 -cert cert.pem -key key.pem

2014年6月30日 星期一

[Linux] 簡易備份加密 MySQL / MySQLDump 資料 @ Ubuntu 14.04

採用 mysqldump 備份 MySQL 資料,可搭配 --where " timestamp < '2014-06-01' AND timestamp >= '2014-05-01' " 等月份備份方式;使用 md5sum 驗證;使用 tar 和 openssl des3 加密:

  • $ mysqldump -u root -p myDatabase myTable --where " timestamp < '2014-06-01' AND timestamp >= '2014-05-01' " > mydatabase_mytable.2014-06.sql
  • $ find * -name "*.sql" -exec sh -c 'test -e {}.md5sum || md5sum {} > {}.md5sum' \; 
  • $ find * -name "*.sql" -exec sh -c 'tar -zcf - {} {}.md5sum | openssl des3 -salt -k MyPassword | dd of={}.tgz.des3' \;
連續動作:
  • $ find * -name "*.sql" -exec sh -c 'test -e {}.md5sum || md5sum {} > {}.md5sum' \; && md5sum -c *.md5sum > /dev/null && find * -name "*.sql" -exec sh -c 'test -e {}.tgz.des3 || tar -zcf - {} {}.md5sum | openssl des3 -salt -k MyPassword | dd of={}.tgz.des3' \;
如此一來,即可透過 crontab 定期一直加密新增的 *.sql 檔案(大概要處理一下 md5sum 的指令驗證那塊),加密後就可以隨意丟一堆雲端儲存服務了吧