openssl为了支持可插拔的算法采用了engine,这里面有一些专利原因和政治原因,暂且掠过。在说engine之前首先看看算法的组织方式,其实如果你完全明白了这种组织,那么engine就是一个自然而然的结果了。首先看一下openssl中是如何组织算法的:
图表已经很清晰了,如果非要解释一下的话,那么就看下面的文字:openssl首先将所有的算法分成几个大的类别,每一个类别有一个所谓的table表示,比如rsa,dsa,cipher等等,然后在每一个大的类别中再细分为若干小类,对于这一点,如果你仅仅看rsa那么很难看明白,毕竟大家几乎都知道rsa好像只有一种算法,就是rsa算法,事实上并不是这样的,比如考虑cipher,我们就会看出为何这么看是不对的,cipher是所有对称算法的总称,由aes,des,3des等组成,对于这个例子,那么aes,des,3des就在上图中占据一个椭圆形的冲突节点,之所以用哈希再组织我认为是为了查找的迅速,如果仅仅有几种算法的table,完全没有必要用哈希表去组织,事实上,对于大多数的table,其哈希值算法就是简单返回算法的算法ID,这在算法ID唯一的系统中就唯一定位了一个算法。算法既然被定位了,那么接下来就要定位它的实现了,众所周知一个算法可以有很多种不同的实现,那么具体要选用哪一种呢,如果没有提供额外的信息,那么首先就要通过算法ID利用哈希算法定位到一个算法(哈希定位用table的哈希算法,冲突链定位用比较算法),然后选取默认的算法实现,那么如果一个调用者提供了一些额外的信息呢,比如调用者能否调用自己的算法而不使用默认的实现呢?这就是engine的意义,事实上一个engine包含了所有的算法,也就是所有的table中的每一个算法,每一个算法都提供一个实现(也可以不提供,用默认实现填充),然后调用时用engine和算法id作为参数就可以了,一个engine必须有能力通过一个算法的id来选出一个算法的实现,比如对于cipher而言,engine提供了一个回调函数,该函数的目的是通过算法id来得到一个EVP_CIPHER。
上图中给定了一个算法id和一个engine,选择一个实现所使用的原则是优先适用原则,只选择第一个可用的实现
我故意省略了engine的实现,为了当我遗忘的时候能够有个思考的过程。我们看一下ssl的握手过程中的算法确定,首先说一个简单的,那就是客户端rsa结构体的确定,其实结构体rsa中的很多参数是服务器传过来的,客户端通过d2i操作解码了参数,下面看一个更加实际的,服务器传来一个算法id,客户端通过以参数engine为NULL调用EVP_CipherInit_ex,得到的结果就是:
else
impl = ENGINE_get_cipher_engine(cipher->nid);
if(impl){
const EVP_CIPHER *c = ENGINE_get_cipher(impl, cipher->nid);
这个结果说明了一切,另外看看RSA_new这个函数。
本文转自 dog250 51CTO博客,原文链接:http://blog.51cto.com/dog250/1271988