/* * smb2_sign_check_request * * Calculates MAC signature for the request mbuf chain * using the next expected sequence number and compares * it to the given signature. * * Note it does not check the signature for secondary transactions * as their sequence number is the same as the original request. * * Return 0 if the signature verifies, otherwise, returns -1; * */ int smb2_sign_check_request(smb_request_t *sr) { uint8_t req_sig[SMB2_SIG_SIZE]; uint8_t digest[SHA256_DIGEST_LENGTH]; struct mbuf_chain *mbc = &sr->smb_data; struct smb_sign *sign = &sr->session->signing; int sig_off; /* * Don't check commands with a zero session ID. * [MS-SMB2] 3.3.4.1.1 */ if (sr->smb_uid == 0) return (0); /* Get the request signature. */ sig_off = sr->smb2_cmd_hdr + SMB2_SIG_OFFS; if (smb_mbc_peek(mbc, sig_off, "#c", SMB2_SIG_SIZE, req_sig) != 0) return (-1); /* Compute what we think it should be. */ if (smb2_sign_calc(mbc, sign, digest) != 0) return (-1); if (memcmp(digest, req_sig, SMB2_SIG_SIZE) != 0) { cmn_err(CE_NOTE, "smb2_sign_check_request: bad signature"); return (-1); } return (0); }
/* * smb2_sign_check_request * * Calculates MAC signature for the request mbuf chain * using the next expected sequence number and compares * it to the given signature. * * Note it does not check the signature for secondary transactions * as their sequence number is the same as the original request. * * Return 0 if the signature verifies, otherwise, returns -1; * */ int smb2_sign_check_request(smb_request_t *sr) { uint8_t req_sig[SMB2_SIG_SIZE]; uint8_t vfy_sig[SMB2_SIG_SIZE]; struct mbuf_chain *mbc = &sr->smb_data; smb_session_t *s = sr->session; smb_user_t *u = sr->uid_user; int sig_off; /* * Don't check commands with a zero session ID. * [MS-SMB2] 3.3.4.1.1 */ if (sr->smb_uid == 0 || u == NULL) return (0); /* In case _sign_begin failed. */ if (s->sign_calc == NULL) return (-1); /* Get the request signature. */ sig_off = sr->smb2_cmd_hdr + SMB2_SIG_OFFS; if (smb_mbc_peek(mbc, sig_off, "#c", SMB2_SIG_SIZE, req_sig) != 0) return (-1); /* * Compute the correct signature and compare. * smb2_sign_calc() or smb3_sign_calc() */ if (s->sign_calc(sr, mbc, vfy_sig) != 0) return (-1); if (memcmp(vfy_sig, req_sig, SMB2_SIG_SIZE) != 0) { cmn_err(CE_NOTE, "smb2_sign_check_request: bad signature"); return (-1); } return (0); }
static int smb2_sign_calc_common(smb_request_t *sr, struct mbuf_chain *mbc, uint8_t *digest, mac_ops_t *ops) { uint8_t tmp_hdr[SMB2_HDR_SIZE]; smb_sign_ctx_t ctx = 0; smb_session_t *s = sr->session; smb_user_t *u = sr->uid_user; struct smb_key *sign_key = &u->u_sign_key; struct mbuf *mbuf; int offset, resid, tlen, rc; if (s->sign_mech == NULL || sign_key->len == 0) return (-1); /* smb2_hmac_init or smb3_cmac_init */ rc = ops->mac_init(&ctx, s->sign_mech, sign_key->key, sign_key->len); if (rc != 0) return (rc); /* * Work with a copy of the SMB2 header so we can * clear the signature field without modifying * the original message. */ tlen = SMB2_HDR_SIZE; offset = mbc->chain_offset; resid = mbc->max_bytes - offset; if (smb_mbc_peek(mbc, offset, "#c", tlen, tmp_hdr) != 0) return (-1); bzero(tmp_hdr + SMB2_SIG_OFFS, SMB2_SIG_SIZE); /* smb2_hmac_update or smb3_cmac_update */ if ((rc = ops->mac_update(ctx, tmp_hdr, tlen)) != 0) return (rc); offset += tlen; resid -= tlen; /* * Digest the rest of the SMB packet, starting at the data * just after the SMB header. * * Advance to the src mbuf where we start digesting. */ mbuf = mbc->chain; while (mbuf != NULL && (offset >= mbuf->m_len)) { offset -= mbuf->m_len; mbuf = mbuf->m_next; } if (mbuf == NULL) return (-1); /* * Digest the remainder of this mbuf, limited to the * residual count, and starting at the current offset. * (typically SMB2_HDR_SIZE) */ tlen = mbuf->m_len - offset; if (tlen > resid) tlen = resid; /* smb2_hmac_update or smb3_cmac_update */ rc = ops->mac_update(ctx, (uint8_t *)mbuf->m_data + offset, tlen); if (rc != 0) return (rc); resid -= tlen; /* * Digest any more mbufs in the chain. */ while (resid > 0) { mbuf = mbuf->m_next; if (mbuf == NULL) return (-1); tlen = mbuf->m_len; if (tlen > resid) tlen = resid; rc = ops->mac_update(ctx, (uint8_t *)mbuf->m_data, tlen); if (rc != 0) return (rc); resid -= tlen; } /* * smb2_hmac_final or smb3_cmac_final * Note: digest is _always_ SMB2_SIG_SIZE, * even if the mech uses a longer one. * * smb2_hmac_update or smb3_cmac_update */ if ((rc = ops->mac_final(ctx, digest)) != 0) return (rc); return (0); }
/* * smb2_sign_calc * * Calculates MAC signature for the given buffer and returns * it in the mac_sign parameter. * * The sequence number is in the last 16 bytes of the SMB2 header. * The signature algorighm is to compute HMAC SHA256 over the * entire command, with the signature field set to zeros. * * Return 0 if success else -1 */ int smb2_sign_calc(struct mbuf_chain *mbc, struct smb_sign *sign, uint8_t *digest) { sha2_hc_ctx_t hctx; uint8_t tmp_hdr[SMB2_HDR_SIZE]; struct mbuf *mbuf; int offset = mbc->chain_offset; int resid = mbc->max_bytes - offset; int tlen; if (sign->mackey == NULL) return (-1); bzero(&hctx, sizeof (hctx)); if (smb2_hmac_sha256_init(&hctx, sign->mackey, sign->mackey_len)) return (-1); /* * Work with a copy of the SMB2 header so we can * clear the signature field without modifying * the original message. */ tlen = SMB2_HDR_SIZE; if (smb_mbc_peek(mbc, offset, "#c", tlen, tmp_hdr) != 0) return (-1); bzero(tmp_hdr + SMB2_SIG_OFFS, SMB2_SIG_SIZE); smb2_hmac_sha256_update(&hctx, tmp_hdr, tlen); offset += tlen; resid -= tlen; /* * Digest the rest of the SMB packet, starting at the data * just after the SMB header. * * Advance to the src mbuf where we start digesting. */ mbuf = mbc->chain; while (mbuf != NULL && (offset >= mbuf->m_len)) { offset -= mbuf->m_len; mbuf = mbuf->m_next; } if (mbuf == NULL) return (-1); /* * Digest the remainder of this mbuf, limited to the * residual count, and starting at the current offset. * (typically SMB2_HDR_SIZE) */ tlen = mbuf->m_len - offset; if (tlen > resid) tlen = resid; smb2_hmac_sha256_update(&hctx, (uint8_t *)mbuf->m_data + offset, tlen); resid -= tlen; /* * Digest any more mbufs in the chain. */ while (resid > 0) { mbuf = mbuf->m_next; if (mbuf == NULL) return (-1); tlen = mbuf->m_len; if (tlen > resid) tlen = resid; smb2_hmac_sha256_update(&hctx, (uint8_t *)mbuf->m_data, tlen); resid -= tlen; } smb2_hmac_sha256_final(&hctx, digest); return (0); }