@@ -16,6 +16,8 @@ package sip
1616
1717import (
1818 "context"
19+ "crypto/sha256"
20+ "encoding/hex"
1921 "fmt"
2022 "log/slog"
2123 "math"
@@ -55,6 +57,15 @@ const (
5557 audioBridgeMaxDelay = 1 * time .Second
5658)
5759
60+ // hashPassword creates a SHA256 hash of the password for logging purposes
61+ func hashPassword (password string ) string {
62+ if password == "" {
63+ return "<empty>"
64+ }
65+ hash := sha256 .Sum256 ([]byte (password ))
66+ return hex .EncodeToString (hash [:8 ]) // Use first 8 bytes for shorter hash
67+ }
68+
5869func (s * Server ) getInvite (from string ) * inProgressInvite {
5970 s .imu .Lock ()
6071 defer s .imu .Unlock ()
@@ -72,37 +83,81 @@ func (s *Server) getInvite(from string) *inProgressInvite {
7283}
7384
7485func (s * Server ) handleInviteAuth (log logger.Logger , req * sip.Request , tx sip.ServerTransaction , from , username , password string ) (ok bool ) {
86+ log = log .WithValues (
87+ "username" , username ,
88+ "passwordHash" , hashPassword (password ),
89+ "method" , req .Method .String (),
90+ "uri" , req .Recipient .String (),
91+ )
92+
93+ log .Infow ("Starting SIP invite authentication" )
94+
7595 if username == "" || password == "" {
96+ log .Debugw ("Skipping authentication - no credentials provided" )
7697 return true
7798 }
99+
78100 if s .conf .HideInboundPort {
79101 // We will send password request anyway, so might as well signal that the progress is made.
102+ log .Debugw ("Sending processing response due to HideInboundPort config" )
80103 _ = tx .Respond (sip .NewResponseFromRequest (req , 100 , "Processing" , nil ))
81104 }
82105
83106 inviteState := s .getInvite (from )
107+ log = log .WithValues ("inviteStateFrom" , from )
84108
85109 h := req .GetHeader ("Proxy-Authorization" )
86110 if h == nil {
87- log .Infow ("Requesting inbound auth" )
88111 inviteState .challenge = digest.Challenge {
89112 Realm : UserAgent ,
90113 Nonce : fmt .Sprintf ("%d" , time .Now ().UnixMicro ()),
91114 Algorithm : "MD5" ,
92115 }
93116
117+ log .Debugw ("Created digest challenge" ,
118+ "realm" , inviteState .challenge .Realm ,
119+ "nonce" , inviteState .challenge .Nonce ,
120+ "algorithm" , inviteState .challenge .Algorithm ,
121+ )
122+
94123 res := sip .NewResponseFromRequest (req , 407 , "Unauthorized" , nil )
95124 res .AppendHeader (sip .NewHeader ("Proxy-Authenticate" , inviteState .challenge .String ()))
96125 _ = tx .Respond (res )
126+ log .Infow ("No Proxy header found. Sending 407 Unauthorized response with Proxy-Authenticate header" )
97127 return false
98128 }
99129
130+ log .Debugw ("Found Proxy-Authorization header, parsing credentials" )
100131 cred , err := digest .ParseCredentials (h .Value ())
101132 if err != nil {
133+ log .Warnw ("Failed to parse Proxy-Authorization credentials" , err ,
134+ "headerValue" , h .Value (),
135+ )
102136 _ = tx .Respond (sip .NewResponseFromRequest (req , 401 , "Bad credentials" , nil ))
103137 return false
104138 }
105139
140+ // Set credURI and credUsername in logger early to avoid repetitive logging
141+ log = log .WithValues ("credURI" , cred .URI , "credUsername" , cred .Username )
142+
143+ log .Debugw ("Parsed credentials successfully" , "cred" , cred )
144+
145+ // Check if we have a valid challenge state
146+ if inviteState .challenge .Realm == "" {
147+ log .Warnw ("No challenge state found for authentication attempt" , nil ,
148+ "from" , from ,
149+ "expectedRealm" , UserAgent ,
150+ )
151+ _ = tx .Respond (sip .NewResponseFromRequest (req , 401 , "Bad credentials" , nil ))
152+ return false
153+ }
154+
155+ log .Debugw ("Computing digest response" ,
156+ "challengeRealm" , inviteState .challenge .Realm ,
157+ "challengeNonce" , inviteState .challenge .Nonce ,
158+ "challengeAlgorithm" , inviteState .challenge .Algorithm ,
159+ )
160+
106161 digCred , err := digest .Digest (& inviteState .challenge , digest.Options {
107162 Method : req .Method .String (),
108163 URI : cred .URI ,
@@ -111,15 +166,27 @@ func (s *Server) handleInviteAuth(log logger.Logger, req *sip.Request, tx sip.Se
111166 })
112167
113168 if err != nil {
169+ log .Warnw ("Failed to compute digest response" , err )
114170 _ = tx .Respond (sip .NewResponseFromRequest (req , 401 , "Bad credentials" , nil ))
115171 return false
116172 }
117173
174+ log .Debugw ("Digest computation completed" ,
175+ "expectedResponse" , digCred .Response ,
176+ "receivedResponse" , cred .Response ,
177+ "responsesMatch" , cred .Response == digCred .Response ,
178+ )
179+
118180 if cred .Response != digCred .Response {
181+ log .Warnw ("Authentication failed - response mismatch" , nil ,
182+ "expectedResponse" , digCred .Response ,
183+ "receivedResponse" , cred .Response ,
184+ )
119185 _ = tx .Respond (sip .NewResponseFromRequest (req , 401 , "Unauthorized" , nil ))
120186 return false
121187 }
122188
189+ log .Infow ("SIP invite authentication successful" )
123190 return true
124191}
125192
0 commit comments