void SipImpliedSubscriptions::authenticate( const SipMessage& registerMessage ,SipMessage& subscribeRequest ,UtlString& callId ,UtlString& fromTag ,UtlString& fromUri ) { // Construct authentication that the status server will accept // We need the user credentials, and a signed nonce like the one // the status server would have generated to challenge this phone. UtlString user; UtlString realm; UtlString registrationNonce; UtlString opaque; UtlString response; UtlString authUri; // extract the identity from the authorization of the registration if ( registerMessage.getDigestAuthorizationData( &user, &realm // the identity ,NULL // request nonce not used ,&opaque // passed through to aid debugging ,NULL, NULL // response & authUri not used ,HttpMessage::SERVER, 0 ) ) { Url subscribeUser; UtlString passToken; UtlString authType; if (CredentialDB::getInstance()->getCredential( user, realm, subscribeUser ,passToken, authType ) ) { // Construct a nonce UtlString serverNonce; UtlString clientNonce; SipNonceDb* nonceDb = SharedNonceDb::get(); nonceDb->createNewNonce( callId, fromTag, realm ,serverNonce ); // generate a client nonce - doesn't matter what it is, really // because the server doesn't validate this one; // but change an input so that the two won't be the same // UtlString dummyFromTag("different value"); // mRegistrarNonceDb.createNewNonce( callId, dummyFromTag, fromUri // ,clientNonce // ); // Sign the message UtlString responseHash; HttpMessage::buildMd5Digest(passToken.data(), HTTP_MD5_ALGORITHM, serverNonce.data(), NULL, // client nonce 1, // nonce count "", SIP_SUBSCRIBE_METHOD, fromUri.data(), NULL, &responseHash ); subscribeRequest.removeHeader( HTTP_AUTHORIZATION_FIELD, 0); subscribeRequest.setDigestAuthorizationData(user.data(), realm.data(), serverNonce.data(), fromUri.data(), responseHash.data(), HTTP_MD5_ALGORITHM, NULL,//clientNonce.data(), opaque.data(), HTTP_QOP_AUTH, 1, // nonce count HttpMessage::SERVER ); } else { OsSysLog::add( FAC_SIP, PRI_WARNING, "%s implied subscription request not authenticated:\n" " no credentials found for \"%s\"", mLogName.data(), user.data()); } } else { OsSysLog::add( FAC_SIP, PRI_WARNING, "%s implied subscription request not authenticated:\n" " no credentials in registration", mLogName.data() ); } }
void SipImpliedSubscriptions::addAuthorization( const SipMessage& registerMessage ,SipMessage& subscribeRequest ,UtlString& callId ,UtlString& fromTag ,UtlString& fromUri ) { // Construct authentication that the status server will accept // We need the user credentials, and a signed nonce like the one // the status server would have generated to challenge this phone. UtlString user; UtlString userBase; UtlString realm; UtlString registrationNonce; UtlString opaque; UtlString response; UtlString authUri; UtlString qop; UtlString qopType; // Did Register have Authorization header? UtlBoolean registerHasAuth = registerMessage.getDigestAuthorizationData( &user, &realm // the identity ,NULL // request nonce not used ,&opaque // passed through to aid debugging ,NULL, NULL // response & authUri not used ,NULL // cnonce not used ,NULL // nonceCount not used ,&qop // what kind of Auth? ,HttpMessage::SERVER, 0 ,&userBase); // We only support no qop or with qop="auth" HttpMessage::AuthQopValues qopValue = registerMessage.parseQopValue(&qop, qopType); if( registerHasAuth && qopValue < HttpMessage::AUTH_QOP_NOT_SUPPORTED) { Url subscribeUser; UtlString passToken; UtlString authType; if (dataStore().entityDB().getCredential( userBase, realm, subscribeUser ,passToken, authType)) { // Construct a nonce UtlString serverNonce; UtlString clientNonce; UtlString cnonce; UtlString nonceCount; SipNonceDb* nonceDb = SharedNonceDb::get(); nonceDb->createNewNonce( callId, fromTag, realm ,serverNonce ); // Add support for "qop=auth" if requested (eg. cnonce, nonce-count) if (qopValue == HttpMessage::AUTH_QOP_HAS_AUTH) { // Use a random number, anything more adds no value UtlString cnonce; CallId::getNewTag( cnonce ); // We always generate a new nonce, so it's ok to have fixed nonce count nonceCount.append("00000001"); } // Construct A1 UtlString a1Buffer; UtlString encodedA1; a1Buffer.append(user); a1Buffer.append(':'); a1Buffer.append(realm); a1Buffer.append(':'); a1Buffer.append(passToken); NetMd5Codec::encode(a1Buffer.data(), encodedA1); // Sign the message UtlString responseHash; HttpMessage::buildMd5Digest(encodedA1.data(), HTTP_MD5_ALGORITHM, serverNonce.data(), cnonce.data(), // client nonce nonceCount.data(), qopType.data(), SIP_SUBSCRIBE_METHOD, fromUri.data(), NULL, &responseHash ); subscribeRequest.removeHeader( HTTP_AUTHORIZATION_FIELD, 0); subscribeRequest.setDigestAuthorizationData(user.data(), realm.data(), serverNonce.data(), fromUri.data(), responseHash.data(), HTTP_MD5_ALGORITHM, cnonce.data(), opaque.data(), qopType.data(), nonceCount.data(), HttpMessage::SERVER ); } else { Os::Logger::instance().log( FAC_SIP, PRI_WARNING, "%s implied subscription request not authenticated:\n" " no credentials found for \"%s\"", mLogName.data(), userBase.data()); } } else { Os::Logger::instance().log( FAC_SIP, PRI_WARNING, "%s implied subscription request not authenticated:\n" " no credentials in registration", mLogName.data() ); } }