// Decode auth message S3 static int authDecodeS3(struct s_auth_state *authstate, const unsigned char *msg, const int msg_len) { int msgnum; int decmsg_len; unsigned char decmsg[auth_MAXMSGSIZE_S3]; if(msg_len > 6) { memcpy(decmsg, msg, 6); msgnum = utilReadInt16(&decmsg[4]); if(msgnum == (authstate->state + 1)) { decmsg_len = (4 + 2 + cryptoDec(&authstate->crypto_ctx[auth_CRYPTOCTX_CNEG], &decmsg[(4 + 2)], (auth_MAXMSGSIZE_S3 - 2 - 4), &msg[(4 + 2)], (msg_len - 2 - 4), auth_CNEGHMACSIZE, auth_CNEGIVSIZE)); if(decmsg_len >= (4 + 2 + auth_NONCESIZE + seq_SIZE + 4 + 8)) { memcpy(authstate->remote_keygen_nonce, &decmsg[(4 + 2)], auth_NONCESIZE); if((msgnum % 2) == 0) { memcpy(&authstate->keygen_nonce[0], authstate->local_keygen_nonce, auth_NONCESIZE); memcpy(&authstate->keygen_nonce[auth_NONCESIZE], authstate->remote_keygen_nonce, auth_NONCESIZE); } else { memcpy(&authstate->keygen_nonce[0], authstate->remote_keygen_nonce, auth_NONCESIZE); memcpy(&authstate->keygen_nonce[auth_NONCESIZE], authstate->local_keygen_nonce, auth_NONCESIZE); } memcpy(authstate->remote_seq, &decmsg[(4 + 2 + auth_NONCESIZE)], seq_SIZE); authstate->remote_peerid = utilReadInt32(&decmsg[(4 + 2 + auth_NONCESIZE + seq_SIZE)]); memcpy(authstate->remote_flags, &decmsg[(4 + 2 + auth_NONCESIZE + seq_SIZE + 4)], 8); return 1; } } } return 0; }
// decode packet static int packetDecode(struct s_packet_data *data, const unsigned char *pbuf, const int pbuf_size, struct s_crypto *ctx, struct s_seq_state *seqstate) { unsigned char dec_buf[pbuf_size]; int len; // decrypt packet if(pbuf_size < (packet_PEERID_SIZE + packet_HMAC_SIZE + packet_IV_SIZE)) { return 0; } len = cryptoDec(ctx, dec_buf, pbuf_size, &pbuf[packet_PEERID_SIZE], (pbuf_size - packet_PEERID_SIZE), packet_HMAC_SIZE, packet_IV_SIZE); if(len < packet_CRHDR_SIZE) { return 0; }; // get packet data data->peerid = packetGetPeerID(pbuf); data->seq = utilReadInt64(&dec_buf[packet_CRHDR_SEQ_START]); if(seqstate != NULL) if(!seqVerify(seqstate, data->seq)) { return 0; } data->pl_options = dec_buf[packet_CRHDR_PLOPT_START]; data->pl_type = dec_buf[packet_CRHDR_PLTYPE_START]; data->pl_length = utilReadInt16(&dec_buf[packet_CRHDR_PLLEN_START]); if(!(data->pl_length > 0)) { data->pl_length = 0; return 0; } if(len < (packet_CRHDR_SIZE + data->pl_length)) { return 0; } if(data->pl_length > data->pl_buf_size) { return 0; } memcpy(data->pl_buf, &dec_buf[packet_CRHDR_SIZE], data->pl_length); // return length of decoded payload return (data->pl_length); }
// Decode auth message S2 static int authDecodeS2(struct s_auth_state *authstate, const unsigned char *msg, const int msg_len) { int msgnum; int nksize; int signsize; int decmsg_len; unsigned char hmac[auth_HMACSIZE]; unsigned char siginbuf[auth_SIGINBUFSIZE]; unsigned char decmsg[auth_MAXMSGSIZE_S2]; int siginbuf_size; if(msg_len > 10) { memcpy(decmsg, msg, 6); msgnum = utilReadInt16(&decmsg[4]); if(msgnum == (authstate->state + 1)) { decmsg_len = (4 + 2 + cryptoDec(&authstate->crypto_ctx[auth_CRYPTOCTX_IDP], &decmsg[(4 + 2)], (auth_MAXMSGSIZE_S2 - 2 - 4), &msg[(4 + 2)], (msg_len - 2 - 4), auth_IDPHMACSIZE, auth_IDPIVSIZE)); // decrypt IDP layer if(decmsg_len > 10) { nksize = utilReadInt16(&decmsg[(4 + 2)]); if((nksize > nodekey_MINSIZE) && (decmsg_len > (10 + nksize))) { signsize = utilReadInt16(&decmsg[(4 + 4 + nksize)]); if((signsize > 0) && (decmsg_len >= (10 + nksize + signsize + auth_HMACSIZE))) { // check message length if(cryptoHMAC(&authstate->crypto_ctx[auth_CRYPTOCTX_AUTH], hmac, auth_HMACSIZE, &decmsg[(4 + 4)], nksize)) { // generate HMAC tag if(memcmp(&decmsg[(10 + nksize + signsize)], hmac, auth_HMACSIZE) == 0) { // verify HMAC tag if(nodekeyLoadDER(&authstate->remote_nodekey, &decmsg[(4 + 4)], nksize)) { // load remote public key if(memcmp(authstate->remote_nodekey.nodeid.id, authstate->local_nodekey->nodeid.id, nodeid_SIZE) != 0) { // check if remote public key is different from local public key siginbuf_size = authGenRemoteSigIn(authstate, siginbuf, &decmsg[4]); if(rsaVerify(&authstate->remote_nodekey.key, &decmsg[(10 + nksize)], signsize, siginbuf, siginbuf_size)) { // verify signature return 1; } } } } } } } } } } return 0; }