编译android版本openssl共享库

1. 从https://github.com/guardianproject/openssl-android下载Openssl for android源代码

git clone https://github.com/guardianproject/openssl-android.git

2. 改名源代码的目录为jni

mv openssl-android jni

因为jni项目的Android.mk只有在jni目录中才能执行ndk-build命令否则会报错

当时的目录结构应该是这样的:

u@u:~/programs/openssl/openssl_android$ tree jni -L 1
jni
├── android-config.mk
├── AndroidManifest.xml
├── Android.mk
├── android.testssl
├── apps
├── CleanSpec.mk
├── crypto
├── default.properties
├── e_os2.h
├── e_os.h
├── import_openssl.sh
├── include
├── jni
├── libs
├── MODULE_LICENSE_BSD_LIKE
├── NOTICE
├── obj
├── openssl-android
├── openssl.config
├── openssl.version
├── patches
├── README.android
├── README.txt
├── ssl
└── ThirdPartyProject.prop

在jni目录中执行命令ndk-build,没有错误生成四个文件分别如下:

u@u:~/programs/openssl/openssl_android/jni$ ls -l libs/armeabi/
total 1380
-rwxr-xr-x 1 u u 857984 Mar 29 14:57 libcrypto.so
-rwxr-xr-x 1 u u 201472 Mar 29 14:57 libssl.so
-rwxr-xr-x 1 u u 304536 Mar 29 14:57 openssl
-rwxr-xr-x 1 u u 38664 Mar 29 14:57 ssltest

 

使用Openssl进行PKI实践(含多级证书详细步骤)

Openssl是Linux下的基础安全工具

先简要介绍一些基础知识:

Openssl功能主要有:对称加密(DES、3DES、AES等),非对称加密(RSA),散列(MD5、SHA1等)以及证书的相关操作(创建、申请、颁发、吊销等)

PKI体系成为公钥加密体系,组成部分包括:认证中心、注册中心、证书库、证书废止列表。

Openssl常用证书格式:X509、PKCS7、PKCS12。

证书文件常用存储格式:PEM(BASE64)、PFX或P12(二进制)

 

本文主要实践点:

1、根CA相关操作(私钥生成、生成自认证证书)

2、用户证书相关操作(私钥生成、生成证书签发请求文件、根CA同意请求签发该证书)

3、次级CA证书相关操作(从根CA得到次级CA证书和次级CA私钥之后,再给下属用户签发证书)

实验环境:

RHEL 6.3(KVM虚拟机) rootca.testlibq.com

RHEL 6.3(KVM虚拟机) apache.testlibq.com(以APACHE服务器为次级CA)

Windows XP(KVM虚拟机) xp.testlibq.com(以展示证书)

实验步骤:

1、生成根CA证书

登录到ROOTCA机器

cd /etc/pki/CA/private

openssl genrsa -des3 -out rootca.key 1024

#生成ROOTCA私钥,rootca.key格式为PEM

[设置rootca私钥密码,例如输入rootca]

touch /etc/pki/CA/index.txt   #创建证书数据库文件

echo “01” > /etc/pki/CA/serial  #创建证书序号文件

openssl req -new -x509 -key rootca.key -out /etc/pki/CA/rootca.crt

#生成ROOTCA证书(类型为X509),rootca.crt格式为PEM

[输入rootca私钥密码:rootca]

[填入一堆证书信息]

 

由于/etc/pki/tls/openssl.cnf中设置了CA的私钥和证书路径,所以这里使用软链接。

ln -s /etc/pki/CA/private/rootca.key /etc/pki/CA/private/cakey.pem

ln -s /etc/pki/CA/rootca.crt /etc/pki/CA/cacert.pem

这样,CA便设置好了。

查看证书和私钥可以用以下命令:

openssl rsa -in /etc/pki/CA/private/rootca.key -text -noout

openssl x509 -in /etc/pki/CA/rootca.crt -text -noout

 

2、用户证书的相关操作

PS:

用户证书可以在用户端生成私钥和请求文件,然后传递至CA,由CA签发后,发给用户。

也可以由根CA生成用户私钥和请求文件,然后签发后把私钥和证书发给用户。

这里演示后者。

登录到rootca机器(接实验1)

cd /etc/pki/CA/private

openssl genrsa -des3 -out a.key 1024  #生成用户私钥

[set password of a.key]

openssl req -new -key a.key -out a.csr  #生成用户请求文件

[input password of a.key]

[输入一堆证书信息]

openssl ca -in a.csr

[y,y]

 

生成证书位于/etc/pki/CA/newcerts/01.pem

PS:

该证书类型为X509,若需要PKCS12类型证书,请使用

openssl pkcs12 -export -in /etc/pki/CA/newcerts/01.pem -inkey /etc/pki/CA/private/a.key -out a.pfx[输入私钥密码][设置传输密码]

 

3、生成证书链

此节内容网上文章较少,我研究了好久才搞出来。

 

首先上面两个实验是连着做的,第三个实验请把上面的环境清除。

登录到ROOTCA

cd /etc/pki/CA/private

touch ../index.txt

echo “01” > ../serial

openssl genrsa -des3 -out rootca.key 1024 [rootca]

ln -s rootca.key cakey.pem

openssl req -new -x509 -key rootca.key -out /etc/pki/CA/rootca.crt -extensions v3_ca

ln -s /etc/pki/CA/rootca.crt /etc/pki/CA/cacert.pem

这里查看一下rootca证书:

openssl x509 -in /etc/pki/CA/rootca.crt -text -noout

确定extensions中,有basicConstraint CA:TRUE,那么代表正确。

PS:basicConstraint称为基础约束,若有CA:TRUE,证明该证书具有CA效力。(所以上述实验1、2中并不严谨,这点在需要证书链的场合尤为重要)

cd /etc/pki/CA/private

openssl genrsa -des3 -out apache.key 1024 [apache]

openssl req -new -key /etc/pki/CA/private/apache.key -out apache.csr

[apache][一堆证书信息]

openssl ca -in apache.csr -extensions v3_ca[y,y]

PS:这个extensions至关重要,关系到apache这个证书有没有资格再颁发证书给用户。

 

登录到apache主机

rsync rootca.testlibq.com:/etc/pki/CA/private/apache.key /etc/pki/CA/private/apache.key

[root password of rootca.testlibq.com]

rsync rootca.testlibq.com:/etc/pki/CA/newcerts/01.pem /etc/pki/CA/apache.crt

[root password of rootca.testlibq.com]

ln -s /etc/pki/CA/private/apache.key /etc/pki/CA/private/cakey.pem

ln -s /etc/pki/CA/apache.crt /etc/pki/CA/cacert.pem

下面制作用户证书

cd /etc/pki/CA

touch index.txt

echo “01” > serial

openssl genrsa -des3 -out private/user1.key 1024 [user1]

openssl req -new -key private/user1.key -out private/user1.csr[user1][一堆证书信息]

openssl ca -in private/user1.csr -extensions usr_cert[y,y]

PS:这里-extensions usr_cert不必要。

制作证书链

rsync rootca.testlibq.com:/etc/pki/CA/rootca.crt /etc/pki/CA/certs/rootca.crt

[root password of rootca.testlibq.com]

将rootca的证书和apache的证书整合到一个文件

cd /etc/pki/CA/certs

cp /etc/pki/CA/apache.crt chain.pem

cat rootca.crt >> chain.pem

验证证书链

openssl verify -CAfile /etc/pki/CA/certs/chain.crt /etc/pki/CA/newcerts/01.pem

(若显示Verify OK,表示验证证书链成功)

转换用户证书为PKCS12

openssl pkcs12 -export -in /etc/pki/CA/newcerts/01.pem -inkey /etc/pki/CA/private/user1.key -out /etc/pki/CA/private/user1.pfx -chain -CAfile /etc/pki/CA/certs/chain.crt

最后将user1.pfx复制到Windows中,导入证书,便于展示。

结果如图:

 

from : http://liboqiu.blog.51cto.com/1932711/1123537

手动给android APK签名

一、下载openssl-for-windows
例如下载:
下载完毕后直接解压缩,cmd命令进入bin目录下:
openssl genrsa -3 -out testkey.pem 2048
成功生成:testkey.pem  [– 包含私钥的pem文件]
openssl req -new -x509 -key testkey.pem -out testkey.x509.pem -days 10000
[包含公钥的x509 pem文件]
输出错误信息:
Unable to load config info from c:/openssl/ssl/openssl.cnf
只要把openssl目录下的openssl.cnf文件复制到c:/openssl/ssl/目录下即可(目录不存在则手动创建之)。
然后再次输入上述命令后输出:
Loading ‘screen’ into random state – done
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]:cn
State or Province Name (full name) [Some-State]:zhejiang
Locality Name (eg, city) []:hangzhou
Organization Name (eg, company) [Internet Widgits Pty Ltd]:sing
Organizational Unit Name (eg, section) []:sing
Common Name (eg, YOUR name) []:netease
Email Address []:test@163.com
成功生成:testkey.x509.pem
openssl pkcs8 -in testkey.pem -topk8 -outform DER -out testkey.pk8 -nocrypt

成功生成:testkey.pk8 [将私钥pem转为pk8格式]

二、签名
 
signapk.jar testkey.x509.pem  testkey.pk8 HelloJni_test.apk HelloJni_test_signed.apk
 [使用公私钥对apk进行签名]
三、创建批处理命令对APK文件自动化签名
四、验证
import sun.security.pkcs.PKCS7;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

public class Test {
     public static void main(String[] args) throws CertificateException, IOException {
             if(args.length < 1){
                 System.out.println("Error arguments");
                 System.exit(-1);
             }
            FileInputStream fis = new FileInputStream(args[0]);
            PKCS7 pkcs7 = new PKCS7(fis);
            X509Certificate publicKey = pkcs7.getCertificates()[0];

            System.out.println("issuer1:" + publicKey.getIssuerDN());
            System.out.println("subject2:" + publicKey.getSubjectDN());
            System.out.println(publicKey.getPublicKey());
        }
}

输出:

issuer1:EMAILADDRESS=test@163.com, CN=netease, OU=sing, O=sing, L=hangzhou, ST=zhejiang, C=cn
subject2:EMAILADDRESS=test@163.com, CN=netease, OU=sing, O=sing, L=hangzhou, ST=zhejiang, C=cn
Sun RSA public key, 2048 bits
  modulus: 22676173355286459097573334286481325549679742508291213299264044486977814024339605340628711274677072768829606315047576874911034554527084043177679494350712443522287175454777833436168772665418404933643096476891010605269397100182350607109602567424649311950932263840379746712271144600813750815453035262110486680532806609381313030573833526182249935950105614529180848998274172532233764292631298041869124308804566439799309159573665297279480681980653336799995434022140192702337503587221467398087020249337183520598982287860366619939017957775007220964826029614540987113512464831360539897307371766206991936881303261221737921332207
  public exponent: 3
注意:
如果代码出现找不到sun.security.pkcs.PKCS7时,解决方法是:右键工程-Build Path-Config Build Path
点Edit:
点Add,选择Accessible,添加规则:**

openssl建立多级CA签发证书

平时我们自己签发CA证书再签发服务器证书的场景其实都非常简单。浏览器把自签CA导入后,就可以信任由这个CA直接签发的服务器证书。

但是实际上网站使用的证书肯定都不是由根CA直接签发的,比如

淘宝登陆服务器使用的证书。

我之前是自己写了脚本由自签CA直接签发服务器证书,为了真清楚的理解一下证书链的作用就直接使用openssl先签发2层的子CA,再由子CA去签发服务器证书。
手动签发证书的脚本如下:
生成自签CA

点击(此处)折叠或打开

  1. # cat makerootca.sh
  2. #!/bin/bash
  3. DIR=/root/ssl.test2
  4. mkdir -p $DIR/demoCA/{private,newcerts}
  5. touch $DIR/demoCA/index.txt
  6. echo 01 > $DIR/demoCA/serial
  7. openssl genrsa -des3 -out $DIR/demoCA/private/cakey.pem 2048
  8. openssl req -new -x509 -days 3650 -key $DIR/demoCA/private/cakey.pem -out $DIR/demoCA/careq.pem

签发二级CA的脚本

点击(此处)折叠或打开

  1. # cat no2domain.sh
  2. #!/bin/bash
  3. NAME=$1
  4. DIR=$(pwd)/autoget
  5. openssl genrsa -des3 -out $DIR/$NAME.key 2048
  6. openssl rsa -in $DIR/$NAME.key -out $DIR/$NAME.key
  7. openssl req -new -days 3650 -key $DIR/$NAME.key -out $DIR/$NAME.csr
  8. openssl ca -extensions v3_ca -in $DIR/$NAME.csr -config ./openssl.cnf -days 3000 -out $DIR/$NAME.crt -cert $DIR/../demoCA/careq.pem -keyfile $DIR/../demoCA/private/cakey.pem

 

sh no2domain.sh  no2

签发三级CA的脚本

点击(此处)折叠或打开

  1. # cat no3domain.sh
  2. #!/bin/bash
  3. [ $# -ne 1 ] && echo “$0 NAME” && exit
  4. NAME=$1
  5. DIR=$(pwd)/autoget
  6. openssl genrsa -des3 -out $DIR/$NAME.key 2048
  7. openssl rsa -in $DIR/$NAME.key -out $DIR/$NAME.key
  8. openssl req -new -days 3650 -key $DIR/$NAME.key -out $DIR/$NAME.csr
  9. openssl ca -in $DIR/$NAME.csr -extensions v3_ca -config ./openssl.cnf -days 3000 -out $DIR/$NAME.crt -cert $DIR/no2.crt -keyfile $DIR/no2.key

   sh no3domain.sh  no3

由三级CA签发服务器证书的脚本

点击(此处)折叠或打开

  1. # cat no4domain.sh
  2. #!/bin/bash
  3. [ $# -ne 1 ] && echo “$0 NAME” && exit
  4. NAME=$1
  5. DIR=$(pwd)/autoget
  6. openssl genrsa -des3 -out $DIR/$NAME.key 2048
  7. openssl rsa -in $DIR/$NAME.key -out $DIR/$NAME.key
  8. openssl req -new -days 3650 -key $DIR/$NAME.key -out $DIR/$NAME.csr
  9. openssl ca -in $DIR/$NAME.csr -config ./openssl.cnf -days 3000 -out $DIR/$NAME.crt -cert $DIR/no3.crt -keyfile $DIR/no3.key

 sh no4domain.sh my.domain.net

当我们把使用三级CA签发的服务器证书配置在nginx 上时,在已经导入根CA的浏览器上肯定是会遇到证书报警的,然后依次把三级CA(no3.crt  )和二级CA(no2.crt)追加到服务器证书后面,浏览器ssl链接成功,点击证书查看如下图:

existential type crisis : Diagnosis of the OpenSSL Heartbleed Bug

When I wrote about the GnuTLS bug, I said that this isn’t the last severe TLS stack bug we’d see. I didn’t expect it to be quite this bad, however.

The Heartbleed bug is a particularly nasty bug. It allows an attacker to read up to 64KB of memory, and the security researchers have said:

Without using any privileged information or credentials we were able steal from ourselves the secret keys used for our X.509 certificates, user names and passwords, instant messages, emails and business critical documents and communication.

How could this happen? Let’s read the code and find out.

The bug

The fix starts here, in ssl/d1_both.c:

int            
dtls1_process_heartbeat(SSL *s)
    {          
    unsigned char *p = &s->s3->rrec.data[0], *pl;
    unsigned short hbtype;
    unsigned int payload;
    unsigned int padding = 16; /* Use minimum padding */

So, first we get a pointer to the data within an SSLv3 record. That looks like this:

typedef struct ssl3_record_st
    {
        int type;               /* type of record */
        unsigned int length;    /* How many bytes available */
        unsigned int off;       /* read/write offset into 'buf' */
        unsigned char *data;    /* pointer to the record data */
        unsigned char *input;   /* where the decode bytes are */
        unsigned char *comp;    /* only used with decompression - malloc()ed */
        unsigned long epoch;    /* epoch number, needed by DTLS1 */
        unsigned char seq_num[8]; /* sequence number, needed by DTLS1 */
    } SSL3_RECORD;

Records have a type, a length, and data. Back to dtls1_process_heartbeat:

/* Read type and payload length first */
hbtype = *p++;
n2s(p, payload);
pl = p;

The first byte of the SSLv3 record is the heartbeat type. The macro n2s takes two bytes from p, and puts them in payload. This is actually the length of the payload. Note that the actual length in the SSLv3 record is not checked.

The variable pl is then the resulting heartbeat data, supplied by the requester.

Later in the function, it does this:

unsigned char *buffer, *bp;
int r;

/* Allocate memory for the response, size is 1 byte
 * message type, plus 2 bytes payload length, plus
 * payload, plus padding
 */
buffer = OPENSSL_malloc(1 + 2 + payload + padding);
bp = buffer;

So we’re allocating as much memory as the requester asked for: up to 65535+1+2+16, to be precise. The variable bp is going to be the pointer used for accessing this memory. Then:

/* Enter response type, length and copy payload */
*bp++ = TLS1_HB_RESPONSE;
s2n(payload, bp);
memcpy(bp, pl, payload);

The macro s2n does the inverse of n2s: it takes a 16-bit value and puts it into two bytes. So it puts the same payload length requested.

Then it copies payload bytes from pl, the user supplied data, to the newly allocated bparray. After this, it sends this all back to the user. So where’s the bug?

The user controls payload and pl

What if the requester didn’t actually supply payload bytes, like she said she did? What if pl really is only one byte? Then the read from memcpy is going to read whatever memory was near the SSLv3 record and within the same process.

And apparently, there’s a lot of stuff nearby.

There are two ways memory is dynamically allocated with malloc (at least on Linux): using sbrk(2) and using mmap(2). If the memory is allocated with sbrk, then it uses the old heap-grows-up rules and limits what can be found with this, although multiple requests (especially simultaneously) could still find some fun stuff1.

The allocations for bp don’t matter at all, actually. The allocation for pl, however, matters a great deal. It’s almost certainly allocated with sbrk because of the mmapthreshold in malloc. However, interesting stuff (like documents or user info), is very likely to be allocated with mmap and might be reachable from pl. Multiple simultaneous requests will also make some interesting data available.

And your secret keys will probably be available:

The fix

The most important part of the fix was this:

/* Read type and payload length first */
if (1 + 2 + 16 > s->s3->rrec.length)
    return 0; /* silently discard */
hbtype = *p++;
n2s(p, payload);
if (1 + 2 + payload + 16 > s->s3->rrec.length)
    return 0; /* silently discard per RFC 6520 sec. 4 */
pl = p;

This does two things: the first check stops zero-length heartbeats. The second check checks to make sure that the actual record length is sufficiently long. That’s it.

Lessons

What can we learn from this?

I’m a fan of C. It was my first programming language and it was the first language I felt comfortable using professionally. But I see its limitations more clearly now than I have ever before.

Between this and the GnuTLS bug, I think that we need to do three things:

  1. Pay money for security audits of critical security infrastructure like OpenSSL
  2. Write lots of unit and integration tests for these libraries
  3. Start writing alternatives in safer languages

Given how difficult it is to write safe C, I don’t see any other options. I would donate to this effort. Would you?


  1. This section originally contained my skepticism about the feasability of a PoC due to the nature of how the heap works via sbrk. Neel Mehta has validated some of my concerns, but there are many reports of secret key discovery out there. 

Sean is a software engineer who is passionate about doing things right. He is currently working on Squadron: an awesome configuration and release management tool for SaaS applications.

undefined reference to `SHA1’的处理方法

在linux编程使用openssl库时, 有时候编译文件会出现

undefined reference to SHA1 等类似错误

而SHA1在openssl/sha.h文件中已经定义,且在自己的c文件中也include了该openssl/sha.h !!

 

这时候,在编译的时候应该加上-lcrypto -lssl 选项,即可消除编译错误.

例子: c文件:

#include<stdio.h>
#include<stdint.h>
#include <openssl/sha.h>

int main(int argc,char **argv)

{
printf(“hello world\n”);

unsigned char hash[SHA_DIGEST_LENGTH];

unsigned char content[4096] = {‘\x41’};

uint32_t len = 4096;

unsigned char * res = SHA1(content,len,hash);

printf(“digest length = %d\n”,SHA_DIGEST_LENGTH);

printf(“digest hash = %s”,hash);

return 0;
}

编译方法:

gcc -o use_sha use_sha.c -lcrypto -lssl

运行:

./use_sha
hello world
digest length = 20
digest hash = ˘�7_�9J�ɹ�Hs���Pu

已无错误!!