You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

83 lines
2.3 KiB

namespace eval www::digest {
variable noncecount
}
# HTTP/1.1 401 Unauthorized
# WWW-Authenticate: Digest
# realm="testrealm@host.com",
# qop="auth,auth-int",
# nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",
# opaque="5ccc069c403ebaf9f0171e9517f40e41"
proc www::digest::md5 {str} {
package require md5
return [string tolower [::md5::md5 -hex $str]]
}
proc www::digest::sha256 {str} {
package require sha256
return [::sha2::sha256 -hex $str]
}
proc www::digest::digest {challenge username password method uri {body ""}} {
variable noncecount
if {[dict exists $challenge algorithm]} {
set algorithm [dict get $challenge algorithm]
} else {
set algorithm MD5
}
switch $algorithm {
MD5 - MD5-sess {set hash md5}
SHA-256 - SHA-256-sess {set hash sha256}
default {
error "unsupported algorithm: $algorithm"
}
}
set interlude [dict get $challenge nonce]
set keys {username realm nonce uri response}
if {[dict exists $challenge qop]} {
set qops [split [dict get $challenge qop] ,]
if {"auth" in $qops} {
set qop auth
} elseif {"auth-int" in $qops} {
set qop auth-int
} else {
error "unsupported qop: [join $qops {, }]"
}
set nonce [dict get $challenge nonce]
# Generate a random cnonce
set cnonce [format %08x [expr {int(rand() * 0x100000000)}]]
set nc [format %08X [incr noncecount($nonce)]]
append interlude : $nc : $cnonce : $qop
lappend keys qop nc cnonce
if {[dict exists $challenge algorithm]} {lappend keys algorithm}
if {[dict exists $challenge opaque]} {lappend keys opaque}
} else {
set qop auth
}
foreach n $keys {
dict set rc $n \
[if {[dict exists $challenge $n]} {dict get $challenge $n}]
}
dict set rc username $username
dict set rc uri $uri
if {[dict exists $rc qop]} {
dict set rc qop $qop
dict set rc cnonce $cnonce
dict set rc nc $nc
}
set A1 [$hash $username:[dict get $challenge realm]:$password]
if {[string match {*-sess} $algorithm]} {append A1 : $nonce : $cnonce}
set A2 [$hash $method:$uri]
if {$qop eq "auth-int"} {append A2 : $body}
dict set rc response [$hash $A1:$interlude:$A2]
set authlist {}
dict for {key val} $rc {
if {$key ni {qop nc}} {
lappend authlist [format {%s="%s"} $key $val]
} else {
lappend authlist $key=$val
}
}
return "Digest [join $authlist ,]"
}