bool TMsg::validateAuthInfo(char *buf, int bufSize, AuthProtocols proto, const DigestTypesLst& acceptedDigestTypes) { bool is_ok = false; bool dt_in_list = false; switch (proto) { case AUTH_PROTO_NOT_SUPPORTED: case AUTH_PROTO_NONE: return true; case AUTH_PROTO_DELAYED: { SPtr<TOptAuthentication> auth = (Ptr*)getOption(OPTION_AUTH); if (!auth) { Log(Warning) << "AUTH: Mandatory AUTH option missing in delayed auth." << LogEnd; return false; } if (auth->getProto() != AUTH_PROTO_DELAYED) { Log(Warning) << "AUTH: Bad protocol in auth: expected 2(delayed auth), but got " << int(auth->getProto()) << ", key ignored." << LogEnd; return false; } if (auth->getAlgorithm() != 1) { Log(Warning) << "AUTH: Bad algorithm in auth option: expected 1 (HMAC-MD5), but got " << int(auth->getAlgorithm()) << ", key ignored." << LogEnd; return false; } if (MsgType == SOLICIT_MSG) { if (auth->getSize() != TOptAuthentication::OPT_AUTH_FIXED_SIZE + TOpt::OPTION6_HDR_LEN) { Log(Warning) << "AUTH: Received non-empty delayed-auth option in SOLICIT," << " expected empty." << LogEnd; return false; } else { return true; // delayed auth in Solicit should come in empty } } if (SPI_ == 0) { Log(Warning) << "AUTH: Received invalid SPI = 0." << LogEnd; return false; } if (!loadAuthKey()) { Log(Warning) << "AUTH: Failed to load delayed auth key with key id=" << std::hex << getSPI() << std::dec << LogEnd; return false; } // Ok, let's do validation char *rcvdAuthInfo = new char[RECONFIGURE_DIGEST_SIZE]; char *goodAuthInfo = new char[RECONFIGURE_DIGEST_SIZE]; memmove(rcvdAuthInfo, AuthDigestPtr_, DELAYED_AUTH_DIGEST_SIZE); memset(AuthDigestPtr_, 0, DELAYED_AUTH_DIGEST_SIZE); hmac_md5(buf, bufSize, (char*)&AuthKey_[0], AuthKey_.size(), goodAuthInfo); Log(Debug) << "Auth: Checking delayed-auth (HMAC-MD5) digest:" << LogEnd; PrintHex("Auth:received digest: ", (uint8_t*)rcvdAuthInfo, DELAYED_AUTH_DIGEST_SIZE); PrintHex("Auth: proper digest: ", (uint8_t*)goodAuthInfo, DELAYED_AUTH_DIGEST_SIZE); if (0 == memcmp(goodAuthInfo, rcvdAuthInfo, DELAYED_AUTH_DIGEST_SIZE)) is_ok = true; delete [] rcvdAuthInfo; delete [] goodAuthInfo; return is_ok; } case AUTH_PROTO_RECONFIGURE_KEY: { if (MsgType != RECONFIGURE_MSG) return true; SPtr<TOptAuthentication> auth = (Ptr*)getOption(OPTION_AUTH); if (!auth) { Log(Warning) << "AUTH: Mandatory AUTH option missing in RECONFIGURE." << LogEnd; return false; } if (auth->getProto() != AUTH_PROTO_RECONFIGURE_KEY) { Log(Warning) << "AUTH: Bad protocol in auth: expected 3(reconfigure-key), but got " << int(auth->getProto()) << ", key ignored." << LogEnd; return false; } if (auth->getAlgorithm() != 1) { Log(Warning) << "AUTH: Bad algorithm in auth option: expected 1, but got " << int(auth->getAlgorithm()) << ", key ignored." << LogEnd; return false; } if (auth->getRDM() != AUTH_REPLAY_NONE) { Log(Warning) << "AUTH: Bad replay detection method (RDM) value: expected 0," << ", but got " << auth->getRDM() << LogEnd; // This is small issue enough, so we can continue. } if (AuthKey_.size() != RECONFIGURE_KEY_SIZE) { Log(Error) << "AUTH: Failed to verify incoming RECONFIGURE message due to " << "reconfigure-key issue: expected size " << RECONFIGURE_KEY_SIZE << ", but got " << AuthKey_.size() << ", message dropped." << LogEnd; return false; } if (!AuthDigestPtr_) { Log(Error) << "AUTH: Failed to verify incoming RECONFIGURE message: " << "AuthDigestPtr_ not set, message dropped." << LogEnd; return false; } char *rcvdAuthInfo = new char[RECONFIGURE_DIGEST_SIZE]; char *goodAuthInfo = new char[RECONFIGURE_DIGEST_SIZE]; memmove(rcvdAuthInfo, AuthDigestPtr_, RECONFIGURE_DIGEST_SIZE); memset(AuthDigestPtr_, 0, RECONFIGURE_DIGEST_SIZE); hmac_md5(buf, bufSize, (char*)&AuthKey_[0], AuthKey_.size(), goodAuthInfo); Log(Debug) << "Auth: Checking reconfigure-key" << LogEnd; PrintHex("Auth:received digest: ", (uint8_t*)rcvdAuthInfo, RECONFIGURE_DIGEST_SIZE); PrintHex("Auth: proper digest: ", (uint8_t*)goodAuthInfo, RECONFIGURE_DIGEST_SIZE); if (0 == memcmp(goodAuthInfo, rcvdAuthInfo, RECONFIGURE_DIGEST_SIZE)) is_ok = true; delete [] rcvdAuthInfo; delete [] goodAuthInfo; return is_ok; } case AUTH_PROTO_DIBBLER: break; } //empty list means that any digest type is accepted if (acceptedDigestTypes.empty()) { dt_in_list = true; } else { // check if the digest is allowed AUTH list for (unsigned i = 0; i < acceptedDigestTypes.size(); ++i) { if (acceptedDigestTypes[i] == DigestType_) { dt_in_list = true; break; } } } if (dt_in_list == false) { if (DigestType_ == DIGEST_NONE) Log(Warning) << "Authentication option is required." << LogEnd; else Log(Warning) << "Authentication method " << getDigestName(DigestType_) << " not accepted." << LogEnd; return false; } if (DigestType_ == DIGEST_NONE) { is_ok = true; } else if (AuthDigestPtr_) { #ifndef MOD_DISABLE_AUTH if (AuthKey_.empty() && !loadAuthKey()) { Log(Debug) << "Auth: Failed to load key with SPI=" << SPI_ << LogEnd; return false; } unsigned AuthInfoLen = getDigestSize(DigestType_); char *rcvdAuthInfo = new char[AuthInfoLen]; char *goodAuthInfo = new char[AuthInfoLen]; memmove(rcvdAuthInfo, AuthDigestPtr_, AuthInfoLen); memset(AuthDigestPtr_, 0, AuthInfoLen); switch (DigestType_) { case DIGEST_PLAIN: /// @todo: load plain text from a file memcpy(goodAuthInfo, "This is 32-byte plain testkey...", 32); break; case DIGEST_HMAC_MD5: hmac_md5(buf, bufSize, (char*)&AuthKey_[0], AuthKey_.size(), goodAuthInfo); break; case DIGEST_HMAC_SHA1: hmac_sha(buf, bufSize, (char*)&AuthKey_[0], AuthKey_.size(), goodAuthInfo, 1); break; case DIGEST_HMAC_SHA224: hmac_sha(buf, bufSize, (char*)&AuthKey_[0], AuthKey_.size(), goodAuthInfo, 224); break; case DIGEST_HMAC_SHA256: hmac_sha(buf, bufSize, (char*)&AuthKey_[0], AuthKey_.size(), goodAuthInfo, 256); break; case DIGEST_HMAC_SHA384: hmac_sha(buf, bufSize, (char*)&AuthKey_[0], AuthKey_.size(), goodAuthInfo, 384); break; case DIGEST_HMAC_SHA512: hmac_sha(buf, bufSize, (char*)&AuthKey_[0], AuthKey_.size(), goodAuthInfo, 512); break; default: break; } if (0 == memcmp(goodAuthInfo, rcvdAuthInfo, AuthInfoLen)) is_ok = true; Log(Debug) << "Auth:Checking using digest method: " << getDigestName(DigestType_) << LogEnd; PrintHex("Auth:received digest: ", (uint8_t*)rcvdAuthInfo, AuthInfoLen); PrintHex("Auth: proper digest: ", (uint8_t*)goodAuthInfo, AuthInfoLen); delete [] rcvdAuthInfo; delete [] goodAuthInfo; if (is_ok) Log(Info) << "Auth: Digest correct." << LogEnd; else { Log(Warning) << "Auth: Digest incorrect." << LogEnd; } #endif } else { Log(Error) << "Auth: Digest mode set to " << DigestType_ << ", but AUTH option not set." << LogEnd; return false; } return is_ok; }
/* prepares binary version of this message, returns number of bytes used **/ int TMsg::storeSelf(char * buffer) { char *start = buffer; int tmp = this->TransID; enum DigestTypes UsedDigestType; if (Bulk) { int tmpSize = this->MsgSize; Log(Debug) <<"MsgSize - DHCP "<<this->MsgSize<< LogEnd; buffer[1]=tmpSize%256; tmpSize/=256; buffer[0]=tmpSize%256; tmpSize/=256; buffer[2]=(char)MsgType; buffer[5] = tmp%256; tmp = tmp/256; buffer[4] = tmp%256; tmp = tmp/256; buffer[3] = tmp%256; tmp = tmp/256; buffer+=6; } else { *(buffer++) = (char)MsgType; /* ugly 3-byte version of htons/htonl */ buffer[2] = tmp%256; tmp = tmp/256; buffer[1] = tmp%256; tmp = tmp/256; buffer[0] = tmp%256; tmp = tmp/256; buffer+=3; } TOptList::iterator option; for (option=Options.begin(); option!=Options.end(); ++option) { (*option)->storeSelf(buffer); buffer += (*option)->getSize(); } #ifndef MOD_DISABLE_AUTH // for AAAAUTH use only HMAC-SHA1 if (getOption(OPTION_AAAAUTH)) UsedDigestType = DIGEST_HMAC_SHA1; else UsedDigestType = DigestType; if (AuthInfoKey && AuthInfoPtr && (getOption(OPTION_AUTH) || getOption(OPTION_AAAAUTH)) && UsedDigestType != DIGEST_NONE) { Log(Debug) << "Auth: Used digest type is " << getDigestName(UsedDigestType) << LogEnd; switch (UsedDigestType) { case DIGEST_PLAIN: memcpy(AuthInfoPtr, "This is 32-byte plain testkey...", getDigestSize(UsedDigestType)); break; case DIGEST_HMAC_MD5: hmac_md5(start, buffer-start, AuthInfoKey, AUTHKEYLEN, (char *)AuthInfoPtr); break; case DIGEST_HMAC_SHA1: hmac_sha(start, buffer-start, AuthInfoKey, AUTHKEYLEN, (char *)AuthInfoPtr, 1); break; case DIGEST_HMAC_SHA224: hmac_sha(start, buffer-start, AuthInfoKey, AUTHKEYLEN, (char *)AuthInfoPtr, 224); break; case DIGEST_HMAC_SHA256: hmac_sha(start, buffer-start, AuthInfoKey, AUTHKEYLEN, (char *)AuthInfoPtr, 256); break; case DIGEST_HMAC_SHA384: hmac_sha(start, buffer-start, AuthInfoKey, AUTHKEYLEN, (char *)AuthInfoPtr, 384); break; case DIGEST_HMAC_SHA512: hmac_sha(start, buffer-start, AuthInfoKey, AUTHKEYLEN, (char *)AuthInfoPtr, 512); break; default: break; } PrintHex("Auth: Sending digest: ", AuthInfoPtr, getDigestSize(UsedDigestType)); } #endif return buffer-start; }
void TMsg::calculateDigests(char* buffer, size_t len) { SPtr<TOptAuthentication> auth = (Ptr*)getOption(OPTION_AUTH); if (!auth) return; switch (auth->getProto()) { default: { Log(Error) << "AUTH: protocol " << auth->getProto() << " not supported yet." << LogEnd; return; } case AUTH_PROTO_DELAYED: { if (AuthKey_.empty()) { if (MsgType == SOLICIT_MSG) { return; // That's alright, no auth info in SOLICIT } Log(Error) << "AUTH: Can't sign delayed-auth option, key empty." << LogEnd; return; } if (auth->getAuthDataPtr()) { hmac_md5(buffer, len, (char*) &AuthKey_[0], AuthKey_.size() ,auth->getAuthDataPtr()); } return; } case AUTH_PROTO_RECONFIGURE_KEY: { if (AuthKey_.size() != RECONFIGURE_KEY_SIZE) { Log(Error) << "AUTH: Invalid size of reconfigure-key: expected " << RECONFIGURE_KEY_SIZE << ", actual size " << AuthKey_.size() << LogEnd; return; } if (auth->getAuthDataPtr()) { hmac_md5(buffer, len, (char*) &AuthKey_[0], AuthKey_.size() ,auth->getAuthDataPtr()); } return; } case AUTH_PROTO_NOT_SUPPORTED: case AUTH_PROTO_NONE: { // don't calculate anything return; } case AUTH_PROTO_DIBBLER: { DigestTypes UsedDigestType; // for AAAAUTH use only HMAC-SHA1 UsedDigestType = DigestType_; if (getSPI() && !loadAuthKey()) { return; } if (getSPI() && !AuthKey_.empty() && UsedDigestType != DIGEST_NONE) { Log(Debug) << "Auth: Used digest type is " << getDigestName(UsedDigestType) << LogEnd; switch (UsedDigestType) { case DIGEST_PLAIN: memcpy(AuthDigestPtr_, "This is 32-byte plain testkey...", getDigestSize(UsedDigestType)); break; case DIGEST_HMAC_MD5: hmac_md5(buffer, len, (char*)&AuthKey_[0], AuthKey_.size(), (char *)AuthDigestPtr_); break; case DIGEST_HMAC_SHA1: hmac_sha(buffer, len, (char*)&AuthKey_[0], AuthKey_.size(), (char *)AuthDigestPtr_, 1); break; case DIGEST_HMAC_SHA224: hmac_sha(buffer, len, (char*)&AuthKey_[0], AuthKey_.size(), (char *)AuthDigestPtr_, 224); break; case DIGEST_HMAC_SHA256: hmac_sha(buffer, len, (char*)&AuthKey_[0], AuthKey_.size(), (char *)AuthDigestPtr_, 256); break; case DIGEST_HMAC_SHA384: hmac_sha(buffer, len, (char*)&AuthKey_[0], AuthKey_.size(), (char *)AuthDigestPtr_, 384); break; case DIGEST_HMAC_SHA512: hmac_sha(buffer, len, (char*)&AuthKey_[0], AuthKey_.size(), (char *)AuthDigestPtr_, 512); break; default: break; } PrintHex(std::string("Auth: Sending digest ") + getDigestName(UsedDigestType) +" : ", (uint8_t*)AuthDigestPtr_, getDigestSize(UsedDigestType)); } } } }