本文档的Copyleft归rosetta所有,使用GPL发布,可以自由拷贝、转载,转载时请保持文档的完整性。
数字签名在网络安全领域用的比较多,可实现用户身份的真实可靠性;实现信息的完整性,确保数据在存储、传输和处理的过程中免遭任何非授权的或非预期的修
改、插入、删除、重发等破坏,从而实现数据的真实性、有效性和一致性;实现抗抵赖性,通过数字签名确保信息的发送方不能抵赖曾经发送的信息,不能否认自己
的操作行为。
下面结合著名的VPN开源项目openswan-2.4.7来理解数字签名和解签名的具体过程。
一、数字签
名和解签(验签)过程:使用hash函数对报文数据生成摘要,使用自己的私钥对摘要进行签名(其实就是加密过程),生成签名数据,把原始数据报文和签名数
据发送给对方。接收方收到原始数据报文和签名数据后,首先使用相同的hash函数对原始数据生成一个摘要,其次,用对方的公钥对签名数据进行解签名(解密
过程),这个解签名的结果也是个摘要,最后比较这两个摘要是否相同,如果相同那么接收方就能确认该数字签名是发送方的。
用以下hash1、hash2和hash3表明不同时期的摘要:
发送方: 签名值=f(hash1(msg),私钥); (msg表示原始报文数据)
接收方:hash2(msg) = f^(-1)(签名值,公钥);(我觉得就是f的反函数,所以写了f^(-1)表示)
hash3(msg);
正常情况下hash2通过公钥对“发送方发过来的签名值”解签后应该等于hash1。hash1和hash3都是对原始报文数据进行摘要,所以只要最后比较hash2和hash3是否相同,就能确定消息的完整性和证明数据是由对方发送的(抗抵赖)。
二、openswan协商总体流程,只关注第5、6个包即可。
Initiator Responder
----------- -----------
HDR, SA -->
第1个包 main_outI1(发送初始化数据1)
<-- HDR, SA
第2个包 main_inI1_outR1(接收到初始化数据1, 发送响应数据1)
HDR, KE, Ni -->
第3个包 main_inR1_outI2(接收到响应数据1,发送初始化数据2)
<-- HDR, KE, Nr
第4个包 main_inI2_outR2(接收到初始化数据2, 发送响应数据2)
HDR*, IDii, [ CERT, ] SIG_I -->
第5个包 main_inR2_outI3(接收到响应数据2,发送初始化数据3)
<-- HDR*, IDir, [ CERT, ] SIG_R
第6个包 main_inI3_outR3(接收到初始化数据3, 发送响应数据3)
main_inR3(接收到响应数据3, 完成主模式协商, 建立ISAKMP SA)
由rfc2409 5.1 使用签名方法进行IKE第一阶段认证,可知签名载荷SIG_I在第5个包中发送给对方,对方在第6个包中对签名进行验签,并发送另外一个签名给发起方,最后发起方对收到的签名进行验签。
5.1 使用签名方法进行IKE第一阶段认证
使用签名方法时,在第二个传输往返中交换的辅助信息是当前时间(nonce);
交换的认证是通过对一个相互可得到的hash值进行签名。使用签名认证的主模
式描述如下:
发起者 响应者
----------- -----------
HDR, SA -->
<-- HDR, SA
HDR, KE, Ni -->
<-- HDR, KE, Nr
HDR*, IDii, [ CERT, ] SIG_I -->
<-- HDR*, IDir, [ CERT, ] SIG_R
三、签名过程
1,函数调用过程:
main_inR2_outI3()
->main_mode_hash()
->RSA_sign_hash()
->sign_hash()
2,具体分析(只是摘取关键代码片段):
main_inR2_outI3()
{
/* HASH_I or SIG_I out */
{
u_char hash_val[MAX_DIGEST_LEN];
size_t hash_len = main_mode_hash(st, hash_val, TRUE,
&id_pbs);//对数据st和id_pbs做摘要(即原始数据msg),摘要值放在hash_val中(即hash1),摘要长度为返回值
hash_len。
if (auth_payload == ISAKMP_NEXT_HASH)
{
/* HASH_I out */
if (!out_generic_raw(ISAKMP_NEXT_NONE
, &isakmp_hash_desc
, &md->rbody
, hash_val, hash_len, "HASH_I"))
return STF_INTERNAL_ERROR;
}
else
{
/* SIG_I out */
u_char sig_val[RSA_MAX_OCTETS];
size_t sig_len = RSA_sign_hash(st->st_connection
, sig_val, hash_val,
hash_len);//对摘要值hash_val(hash1)做签名,签名使用的证书私钥放在st->st_connection中,最终的签
名值为sig_val,长度为返回值sig_len.
if (sig_len == 0)
{
loglog(RC_LOG_SERIOUS, "unable to locate my private key for RSA Signature");
return STF_FAIL + AUTHENTICATION_FAILED;
}
if (!out_generic_raw(ISAKMP_NEXT_NONE
, &isakmp_signature_desc
, &md->rbody
, sig_val
, "SIG_I"))
return STF_INTERNAL_ERROR;
}
}
}
//hash函数
static size_t /* length of hash */
main_mode_hash(struct state *st
, u_char *hash_val /* resulting bytes */
, bool hashi /* Initiator? */
, const pb_stream *idpl) /* ID payload, as PBS; cur must be at end */
{
struct hmac_ctx ctx;
hmac_init_chunk(&ctx, st->st_oakley.hasher, st->st_skeyid);
main_mode_hash_body(st, hashi, idpl, &ctx.hash_ctx, ctx.h->hash_update);
hmac_final(hash_val, &ctx);
return ctx.hmac_digest_len;
}
//签名函数
static size_t
RSA_sign_hash(struct connection *c
, u_char sig_val[RSA_MAX_OCTETS]
, const u_char *hash_val, size_t hash_len)
{
size_t sz = 0;
smartcard_t *sc = c->spd.this.sc;
if (sc == NULL) /* no smartcard */
{
const struct RSA_private_key *k = get_RSA_private_key(c);
if (k == NULL)
return 0; /* failure: no key to use */
sz = k->pub.k;
passert(RSA_MIN_OCTETS <= sz && 4 + hash_len < sz && sz <= RSA_MAX_OCTETS);
sign_hash(k, hash_val, hash_len, sig_val, sz);
}
……
……
}
四、验签过程
1,函数调用关系:
main_inI3_outR3()
->main_inI3_outR3_tail()
->main_id_and_auth()
->oakley_id_and_auth()
->decode_peer_id()//使用ca校验对方证书的合法性,先不关注。
->decode_cert()
->verify_x509cert()
->RSA_check_signature()//验签
->take_a_crack()
->try_RSA_signature()//最终的比较过程
2,具体分析(摘取关键代码片段):
static stf_status
oakley_id_and_auth(struct msg_digest *md
, bool initiator /* are we the Initiator? */
, bool aggrmode /* aggressive mode? */
, cont_fn_t cont_fn /* continuation function */
, const struct key_continuation *kc /* current state, can be NULL */
)
{
struct state *st = md->st;
u_char hash_val[MAX_DIGEST_LEN];
size_t hash_len;
stf_status r = STF_OK;
/* ID Payload in.
* Note: this may switch the connection being used!
*/
if (!decode_peer_id(md, initiator, aggrmode))//使用ca校验对方证书的合法性,先不关注。
return STF_FAIL + INVALID_ID_INFORMATION;
/* Hash the ID Payload.
* main_mode_hash requires idpl->cur to be at end of payload
* so we temporarily set if so.
*/
{
pb_stream *idpl = &md->chain[ISAKMP_NEXT_ID]->pbs;
u_int8_t *old_cur = idpl->cur;
idpl->cur = idpl->roof;
hash_len = main_mode_hash(st, hash_val, !initiator,
idpl);//对数据st和id_pbs做摘要(即发送方的原始数据msg),摘要值放在hash_val中(即hash3),摘要长度为返回值
hash_len。
idpl->cur = old_cur;
}
switch (st->st_oakley.auth)
{
case OAKLEY_PRESHARED_KEY:
{
pb_stream *const hash_pbs = &md->chain[ISAKMP_NEXT_HASH]->pbs;
if (pbs_left(hash_pbs) != hash_len
|| memcmp(hash_pbs->cur, hash_val, hash_len) != 0)
{
DBG_cond_dump(DBG_CRYPT, "received HASH:"
, hash_pbs->cur, pbs_left(hash_pbs));
loglog(RC_LOG_SERIOUS, "received Hash Payload does not match computed value");
/* XXX Could send notification back */
r = STF_FAIL + INVALID_HASH_INFORMATION;
}
}
break;
case OAKLEY_RSA_SIG:
r = RSA_check_signature(st, hash_val, hash_len//hash_val是刚上面计算出来的hash3,这里的st没什么意义,公钥会在函数里取到。
, &md->chain[ISAKMP_NEXT_SIG]->pbs//pbs中存放发送方发过来的签名值
);
……
……
}
RSA_check_signature(struct state *st
, const u_char hash_val[MAX_DIGEST_LEN]
, size_t hash_len
, const pb_stream *sig_pbs
#ifdef USE_KEYRR
, const struct pubkey_list *keys_from_dns
#endif /* USE_KEYRR */
, const struct gw_info *gateways_from_dns
)
{
const struct connection *c = st->st_connection;
struct tac_state s;
err_t dns_ugh = NULL;
s.st = st;
s.hash_val = hash_val;//hash3赋给s
s.hash_len = hash_len;
s.sig_pbs = sig_pbs;//签名值赋给s
s.best_ugh = NULL;
s.tried_cnt = 0;
s.tn = s.tried;
/* try all gateway records hung off c */
if ((c->policy & POLICY_OPPO))
{
struct gw_info *gw;
for (gw = c->gw_info; gw != NULL; gw = gw->next)
{
/* only consider entries that have a key and are for our peer */
if (gw->gw_key_present
&& same_id(&gw->gw_id, &c->spd.that.id)
&& take_a_crack(&s, gw->key, "key saved from DNS TXT"))
return STF_OK;
}
}
/* try all appropriate Public keys */
{
struct pubkey_list *p, **pp;
int pathlen;
pp = &pubkeys;
pathlen = pathlen; /* make sure it used even with !X509 */
{
char buf[IDTOA_BUF];
DBG(DBG_CONTROL,
dntoa_or_null(buf, IDTOA_BUF, c->spd.that.ca, "%any");
DBG_log("required CA is '%s'", buf));
}
for (p = pubkeys; p != NULL; p = *pp)//获取需要使用的公钥,如何获取不再深入。
{
struct pubkey *key = p->key;
if (key->alg == PUBKEY_ALG_RSA && same_id(&c->spd.that.id, &key->id)
&& trusted_ca(key->issuer, c->spd.that.ca, &pathlen))//最终匹配到的对方公钥由指针key指向。
{
time_t now;
{
char buf[IDTOA_BUF];
DBG(DBG_CONTROL,
dntoa_or_null(buf, IDTOA_BUF, key->issuer, "%any");
DBG_log("key issuer CA is '%s'", buf));
}
/* check if found public key has expired */
time(&now);
if (key->until_time != UNDEFINED_TIME && key->until_time < now)
{
loglog(RC_LOG_SERIOUS,
"cached RSA public key has expired and has been deleted");
*pp = free_public_keyentry(p);
continue; /* continue with next public key */
}
if (take_a_crack(&s, key, "preloaded key"))//传入s(包含签名值和hash3)和公钥。
return STF_OK;
}
pp = &p->next;
}
}
……
……
}
take_a_crack(struct tac_state *s
, struct pubkey *kr
, const char *story USED_BY_DEBUG)
{
err_t ugh = try_RSA_signature(s->hash_val, s->hash_len, s->sig_pbs
, kr, s->st);//s->hash_val为hash3, s->sig_pbs为签名值,kr为公钥。
const struct RSA_public_key *k = &kr->u.rsa;
……
……
}
static err_t
try_RSA_signature(const u_char hash_val[MAX_DIGEST_LEN], size_t hash_len
, const pb_stream *sig_pbs, struct pubkey *kr
, struct state *st)
{
……
……
/* We have the decoded hash: see if it matches. */
if (memcmp(hash_val, hash_in_s, hash_len) !=
0)//hash_val还是传进来的hash3,没有变化;hash_in_s是由公钥对签名值进行了解签的结果(即hash2),如中解签名不再分
析。所以这里比较hash3 == hash2 ? 如果相同,那么验签通过,否则失败。
{
DBG_cond_dump(DBG_CRYPT, "decrypted SIG", s, sig_len);
DBG_cond_dump(DBG_CRYPT, "computed HASH", hash_val, hash_len);
/* XXX notification: INVALID_HASH_INFORMATION */
return "9" "authentication failure: received SIG does not match computed HASH, but message is we
}
unreference_key(&st->st_peer_pubkey);
st->st_peer_pubkey = reference_key(kr);
return NULL; /* happy happy */
}
阅读(3086) | 评论(0) | 转发(0) |