yanbin's Blog

自签发 SSL/TLS 证书的方法以及遇到的一些问题

PKI (Public Key Infrastructure, 公开密钥基础架构)简介
0. 目的
PKI 旨在创造、管理、分配、使用、存储以及撤销数字证书
Unix/Linux 平台上常用的 PKI 软件是 openssl.
 
1. 数字证书是什么?
在密码学上视数字证书为一种身份凭证,是一种电子文件,用于证明公开密钥的所有者的身份。
数字证书文件中包含所有者的身份信息、公开密钥信息以及数字证书本身的数字签章;
数字签章用于验证证书文件内容正确无误——没有损坏或者没有被修改过——。
如果签章是正确的,而用户可以相信签署者,之后用户就知道他们可以使用这个密钥,来与密钥的拥有者进行通信。在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
 

0) 指定了 -des3 选项,openssl 要求输入 pass phrase;
pass phraseroot key 的密码;
CA 签发数字证书时需要输入这个密码,算是一种防范措施吧。

1) FIXME: 这种密码也可以用到普通证书的 key,
程序使用证书和 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
0) 关键参数是 -x509:
生成的 root-ca.crt 是一个 self-signed X.509 certificate;

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
 
4) 可以使用如下命令查看 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)

   -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

 

2. 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 {
       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
    $ 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

继续阅读

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".




Host by is-Programmer.com | Power by Chito 1.3.3 beta | © 2007 LinuxGem | Design by Matthew "Agent Spork" McGee