yanbin's Blog
自签发 SSL/TLS 证书的方法以及遇到的一些问题
PKI (Public Key Infrastructure, 公开密钥基础架构)简介
0. 目的
0. 目的
Unix/Linux 平台上常用的 PKI 软件是 openssl.
1. 数字证书是什么?
在密码学上视数字证书为一种身份凭证,是一种电子文件,用于证明公开密钥的所有者的身份。
数字证书文件中包含所有者的身份信息、公开密钥信息以及数字证书本身的数字签章;
数字签章用于验证证书文件内容正确无误——没有损坏或者没有被修改过——。
如果签章是正确的,而用户可以相信签署者,之后用户就知道他们可以使用这个密钥,来与密钥的拥有者进行通信。在X.509中规范了这个认证的过程与标准。①
如果签章是正确的,而用户可以相信签署者,之后用户就知道他们可以使用这个密钥,来与密钥的拥有者进行通信。在X.509中规范了这个认证的过程与标准。①
认证过程中会包含「用 CA 的根(roo)证书验证这份数字证书是由该 CA 签发的」。
用户可以没有自己的数字证书,但是一定需要 CA 的根证书。比如:https 通信。
2. 谁负责创造数字证书?
CA(Certificate Authority) 负责签发数字证书。
CA 由受信任第三方担任,签发数字证书给通信双方使用;有时只签发给服务方,比如: https 通信。
这样理解或许比较简单,互联网上的数字证书签发实际上要复杂。
我们自己签发证书给自己的程序使用,不公开业务也不公开 CA root 证书,可以不用关心太多。
大公司的内部业务也可能足够复杂的到需要 CA,RA 之类的。参见维基百科公开密钥基础建设。
也有 12306 或者银行这样的公司要求用户自己下载它的 CA 的 root 证书。
3. 证书的层级结构。
设置 CA 信息和签发 CA root 证书
0.修改 openssl.conf 文件里的某些域的值。
req_distingushed_name section 可以考虑修改为:
[ req_distinguished_name ] countryName = Country Name (2 letter code) countryName_default = CN stateOrProvinceName = State or Province Name (full name) stateOrProvinceName_default = ShangHai localityName = Locality Name (eg, city) localityName_default = ShangHai 0.organizationName = Organization Name (eg, company) 0.organizationName_default = My Company Name organizationalUnitName = Organizational Unit Name (eg, section) organizationalUnitName_default = May Project
1. 生成 CA root key (根密钥); CA root key 非常重要。
a) 不仅签发或更新 CA root 证书需要。
b) 签发通信双方数字证书时也需要。
Create the keypair:
$ openssl genrsa -des3 -out root-ca.key 1024
$ openssl genrsa -des3 -out root-ca.key 1024
0) 指定了 -des3 选项,openssl 要求输入 pass phrase;
pass phrase 是 root key 的密码;
CA 签发数字证书时需要输入这个密码,算是一种防范措施吧。
1) FIXME: 这种密码也可以用到普通证书的 key,
程序使用证书和 key 时, 一般会要求输入密码,可以作为用户密码用吗?
2) FIXME: 1024 是 key 的长度目前也支持 2048, 这两个值有很大的区别吗?
程序使用证书和 key 时, 一般会要求输入密码,可以作为用户密码用吗?
2) FIXME: 1024 是 key 的长度目前也支持 2048, 这两个值有很大的区别吗?
key 的长度为 2048 会耗费更多的 CPU 资源吧。
2. 自签发 CA 根证书(root certificat)
Use the key to sign itself:
$ openssl req -new -x509 -days 3650 -key root-ca.key -out root-ca.crt -config openssl.cnf
$ openssl req -new -x509 -days 3650 -key root-ca.key -out root-ca.crt -config openssl.cnf
0) 关键参数是 -x509:
生成的 root-ca.crt 是一个 self-signed X.509 certificate;
1) 这条命令将两个步骤合二为一。
a) 使用 private key 生成 certificate request; 需要填写证书持有者的信息;
b) 使用 certificate request 签发证书(singed)或自签发证书(self-signed);
1) 这条命令将两个步骤合二为一。
a) 使用 private key 生成 certificate request; 需要填写证书持有者的信息;
b) 使用 certificate request 签发证书(singed)或自签发证书(self-signed);
2) 这个自签发证书为什么能做为 CA root certificate 使用?
因为指定了参数 -x509, openssl 配置文件 req section 指定了 x509_extensions = v3_ca;
而 v3_ca section 里则有:basicConstraints = CA:true
3) openssl.cnf 以及 CA directory 都不是系统中唯一存在的;
任意创建一个目录,创建配置文件(比如: openssl.cnf),也可以签发根证书。
$ mkdir demoCA && cd demoCA
$ touch index.txt
$ echo 01 > serial
$ mkdir private #指定 private_key=/path/to/demoCA/myCA/private/root-ca.key
$ mkdir myCA # 指定 CA_default:dir=/path/to/demoCA/myCA
任意创建一个目录,创建配置文件(比如: openssl.cnf),也可以签发根证书。
$ mkdir demoCA && cd demoCA
$ touch index.txt
$ echo 01 > serial
$ mkdir private #指定 private_key=/path/to/demoCA/myCA/private/root-ca.key
$ mkdir myCA # 指定 CA_default:dir=/path/to/demoCA/myCA
4) 可以使用如下命令查看 root-ca.crt 的信息
$ openssl x509 -noout -text -in root-ca.crt
$ openssl x509 -noout -text -in root-ca.crt
Regex Unicode 笔记
1. Unicode 字符集使用一个或多个 code point 代表一个字符或者说字符映射到特定的数字上。
2. 字符又分为基本字符和组合字符。
一个基本字符与一个或多个组合字符构成组合序列,用来表示一些非ASCII特殊字符。
比如:
à 这样的音标符号, 表示为 U+0061 (a) + U+0300 (`) 这两个字符的组合;其中 a 是基本字符,
` 是组合字符。
3. 一个字符可以被多个代码点表示.
à 即可表示为: U+0061 和 U+0300 的组合; 为了与 Latin-1 转化方便, à 也表示为 U+00E0,
很可能是法语单词。也就是说 Unicode 代码点与字符间不是一一映射的关系。
类型安全的 max(), min()
类型安全的 max(), min();
#define max(a, b) \ ({ __typeof__ (a) (_a) = (a); \ __typeof__ (b) (_b) = (b); \ _a > _b ? _a : _b; }) #define min(a, b) \ ({ __typeof__ (a) (_a) = (a); \ __typeof__ (b) (_b) = (b); \ _a < _b ? _a : _b; })
AISN C 使用 __typeof__ , GUN C 可以使用 typeof.
valgrind 简单使用
valgrind 是一款 memorycheck 工具,用于 c/c++ 程序的内存检查/调试。
0. 为了使用 valgrind 编译程序时要使用 gcc 的 -g 编译选项,链接libc 的 debug 版本,
自动链接,但是要求有, 如果没有 valgrind 不能正常启动内存检查.
程序用到的其他 C 库也要有 debug 版本的。
也可以使用 gcc 的 -O0 编译选项。据说使用了更好。(大写 O, 数字 0)
自动链接,但是要求有, 如果没有 valgrind 不能正常启动内存检查.
程序用到的其他 C 库也要有 debug 版本的。
也可以使用 gcc 的 -O0 编译选项。据说使用了更好。(大写 O, 数字 0)
-g 是表示编译出的二进制代码中包含调试符号
-O0 是 gcc 的默认选项。可能一些低版本的 gcc 需要加上这个选项。
1. Memorycheck 是 valgrind 的默认工具,--leak-check 选项可以打开 valgrind 详细的 memory leak 探测工具。
$ gcc -O0 -g example.c -o example
$ valgrind --leack-check=yes ./example arg1 arg2
$ gcc -O0 -g example.c -o example
$ valgrind --leack-check=yes ./example arg1 arg2
2. valgrind 的输出。
下面是一个正常分配并正常释放内存的程序用 valgrind 调试的输出:
下面是一个正常分配并正常释放内存的程序用 valgrind 调试的输出:
使用 strtok() 函數要注意,這個函數會改變第一個參數的內容
char *strtok(char *str, const char *delim);
token = strtok(str, "\t "); # 算是安裝要操作的 string; str 指向這個 string;
while (token != NULL)
token = strtok(NULL, "\t "); # 每次操作都會改變第一此安裝的 string 的內容.
0. 第一次安裝後,delim 是可以改變的。
1. 如果在調用 strtok() 後還要正常使用 string 以及她的內容,應該在調用 strtok() 前,
調用 strdup() 複製一份 string 的內容;
用複製的 string 註冊 strtok();
char *dupstr = strdup(str);
token = strtok(dupstr, "\t ");
//...
free(dupstr); // str 指向的內容還在。
伪随机数函数 rand(); srand() 的简单实现
static unsigned long next = 1; static unsigned long myrand(void) { next = next * 1103515245 + 12345; return ((unsigned)(next/65536) % 32768); } static void mysrand(unsigned long speed) { next = speed; } /* example */ int main(int argc, char **argv) { int j, r, nloops; unsigned long speed; if (argc < 2) { fprintf(stderr, "usage: %s <speed> <nloops>\n", argv[0]); exit(EXIT_FAILURE); } speed = strtol(argv[1], NULL, 10); nloops = atoi(argv[2]); mysrand(speed); for (j = 0; j < nloops; ++j) { r = myrand(); fprintf(stderr, "%lu\n", r); } exit(EXIT_SUCCESS); }
bash 中的 -n 操作符判断某个变量为空时应该加上引号("")
bash 中的 -n 操作符判断某个变量为空时应该加上引号("")
不然一个为空的变量也会返回 TRUE.
e.g.
# [ -n $a ] 总是返回 TRUE
a=""
if [ -n $a ]; then
echo "hello" # 永远会执行这里
fi
$ hello
# [ -n "$a" ] 当 a 为 empty 时返回 FALSE
a=""
if [ -n "$a" ]; then
echo "hello" # 不会执行这里
fi
比 alarm() 分辨率更高的 timer: setitimer()
getitimer, setitimer - get or set value of an interval timer
int getitimer(int which, struct itimerval *curr_value);
int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value);
seitimer() 设置三個 process 的内部定时器中的某一個, getitimer() 获得这三個定时器中某一個信息。
每一个 process 都有三个不同类型的定时器,which 的值对应:
ITIMER_REAL /* 运行在 real time, 定时器到期时提交 SIGALRM 信号 和 alarm()
* 提交给进程的是同一个信号。
*/
ITIMER_VIRTUAL // 运行在 process 运行时,定时器到期时提交 SIGVTALRM 信号
ITIMER_PROF // 运行在 process 运行或在后台运行时,定时器到期时提交 SIGPROF 信号
struct itimerval {
struct timeval it_interval; /* next value */
struct timeval it_value; /* current value */
};
struct timeval it_interval; /* next value */
struct timeval it_value; /* current value */
};
struct timeval {
time_t tv_sec; /* seconds */
suseconds_t tv_usec; /* microseconds */
};
time_t tv_sec; /* seconds */
suseconds_t tv_usec; /* microseconds */
};
0. 設置 it_value.tv_sec > 0 || it_value.tv_usec > 0 timer 開始運行,
並且在固定頻率減少 it_value.tv_sec 和/或 it_value.tv_usec 的值。
可以說 it_value 是 timer 的剩餘值。
1. 當 it_value.tv_sec == 0 && it_value.tv_usec == 0 時, timer expire。
直接設置 it_value.tv_sec == 0 && it_value.tv_usec == 0 那麼 timer expire。
NOTE: 對 timer it_value 的檢查可能會在一定的時間之後才會到來,
所以不能假設清空了 it_value 就會 timer expire.
2. 一個 timer period 到期時,用 it_interval 的值初始化 it_value 開始下一個週期,
如果 it_interval.tv_sec > 0 || it_interval.tv_usec > 0 話。
那麼用 it_interval 的值初始化 it_value 開始下一個 timer period
3. 可以同時清空 it_interval 和 it_value 可以讓 timer 停止運行。
Debian 7.6 Wheezy 安装 Intel® Wireless 7260 wifi 模块驱动和固件的方法。
Debian 7.6 Wheezy 安装 Intel® Wireless 7260 wifi 模块驱动和固件的方法。
0. 内核以及发行版 Version 信息
Debian 7.6 Wheezy
Linux fyp-tp 3.2.0-4-amd64 #1 SMP Debian 3.2.60-1+deb7u3 x86_64 GNU/Linux
1. 获得 PCI device numbric ID
$ lspci -nn # 可以显示设备号和subsystem ID
....
04:00.0 Network controller [0280]: Intel Corporation Device [8086:08b2](rev 6b)
在下面的网站可以根据设备号(0x808) 和 subsystem ID(0x08b2) 查找到设备型号:
http://pci-ids.ucw.cz/read/PC
可知 wifi 模块的型号是: Intel Wireless 7260
2. google 可知这个 wifi 模块使用 iwlwifi wireless driver。
这个驱动包在 Debain nofree 源中。 使用 Debian nofree 源:
$ sudo echo '# Debian 7 "Wheezy"' >> /etc/apt/sources.list
0. 内核以及发行版 Version 信息
Debian 7.6 Wheezy
Linux fyp-tp 3.2.0-4-amd64 #1 SMP Debian 3.2.60-1+deb7u3 x86_64 GNU/Linux
1. 获得 PCI device numbric ID
$ lspci -nn # 可以显示设备号和subsystem ID
....
04:00.0 Network controller [0280]: Intel Corporation Device [8086:08b2](rev 6b)
在下面的网站可以根据设备号(0x808) 和 subsystem ID(0x08b2) 查找到设备型号:
http://pci-ids.ucw.cz/read/PC
可知 wifi 模块的型号是: Intel Wireless 7260
2. google 可知这个 wifi 模块使用 iwlwifi wireless driver。
这个驱动包在 Debain nofree 源中。 使用 Debian nofree 源:
$ sudo echo '# Debian 7 "Wheezy"' >> /etc/apt/sources.list
$ sudo echo "deb http://http.debian.net/debian/ wheezy main contribnon-free" >> /etc/apt/sources.list
安装完驱动后,要安装相应的固件,可以在
http://wireless.kernel.org/en/users/Drivers/iwlwifi
找到相应的固件包, 解压后使用 root 用户安装:
$ cp iwlwifi-*.ucode /lib/firmware
安装完驱动后,要安装相应的固件,可以在
http://wireless.kernel.org/en/users/Drivers/iwlwifi
找到相应的固件包, 解压后使用 root 用户安装:
$ cp iwlwifi-*.ucode /lib/firmware
shell 管道两端的程序,并不是左边的程序先启动
$ ps aux | grep "demo"
这条命令中的 ps 先启动,会导致程序异常退出。
因为写一个没有读端的管道,引发 SIGPIPE 信号,SIGPIPE 信号默认行为是终止程序的执行。
管道的创建者(shell) 先创建管道,启动 read 管道的程序 (grep), 再启动 write 管道的程序(ps aux).
读一个没有写端的管道会阻塞,grep 可以接受阻塞。
$ ps aux | grep "demo" | grep -v "grep"
这样的命令相当于: (ps aux | grep "demo") | grep -v "grep".