2.5 DIGEST-MD5
come meccanismo SASL
(RFC-2831)
Descriviamo qui come usare Digest come un meccanismo di autenticazione per il protocollo SASL.
Se il client non si è ancora autenticato al server, deve anzitutto effettuare l’autenticazione iniziale che descriviamo in questo paragrafo.
Passo Uno
Il server inizia mandando un challenge. I dati
inclusi in questo challenge contengono alcune stringe
strutturate secondo le regole della digest challenge. Abbiamo:
digest-challenge =
1#( realm | nonce | qop-options | stale | maxbuf | charset
algorithm | cipher-opts | auth-param )
realm = "realm" "=" <"> realm-value <">
realm-value = qdstr-val
nonce = "nonce" "=" <"> nonce-value <">
nonce-value = qdstr-val
qop-options = "qop" "=" <"> qop-list <">
qop-list = 1#qop-value
qop-value = "auth" | "auth-int" | "auth-conf" |
token
stale = "stale" "=" "true"
maxbuf = "maxbuf" "=" maxbuf-value
maxbuf-value = 1*DIGIT
charset = "charset" "=" "utf-8"
algorithm = "algorithm" "=" "md5-sess"
cipher-opts = "cipher" "=" <"> 1#cipher-value <">
cipher-value = "3des" | "des" | "rc4-40" | "rc4" |
"rc4-56" | token
auth-param = token "=" ( token | quoted-string )
Sinteticamente descriviamo il significato di ogni campo.
·
realm
E’ una stringa che dà la possibilità ad un utente di conoscere quale username e password utilizzare, nel caso che l’utente
abbia differenti username e password per ogni server.
Concettualmente,è il nome di un insieme di account che
include l’account dell’utente che si sta autenticando.
·
nonce
È una stringa specificata dal server che deve essere differente ogni volta che
una digest challenge è
inviata come parte dell’autenticazione iniziale. Il contenuto di questa
stringa dipende dall’implementazione del protocollo.
·
qop-options
È una stringa di uno o più token che indicano la
qualità della protezione supportata dal server. Il valore auth indica l’autenticazione; il valore auth-int indica autenticazione con garanzia
sull’integrità dei dati; il valore auth-conf
indica autenticazione con integrità dei dati e crittografia. Il valore
di default è auth.
·
stale
Questo valore non è usato nell’autenticazione iniziale.
·
maxbuf
Questo valore indica la dimensione del più grande buffer che il server può
supportare nell’autenticazione auth-int e auth-conf.
·
charset
Questa direttiva, se presente, specifica se il server supporta lo schema di
caratteri UTF-8 per la codifica dello username e
della password.
·
algorithm
Questo valore è richiesto per la compatibilità col protocollo HTTP Digest, che supporta altri algoritmi.
·
cipher-opts
Contiene la lista delle modalità di cifratura che il server supporta. Questa
lista è presente solo se è settato il valore auth-conf
nel campo qop-options. I valori possibili sono:
des, che indica l’algoritmo
DES nella modalità CBC con
una chiave a 56 bit; 3des, che indica l’algoritmo EDE, o del triplo
DES, sempre in modalità CBC; rc4, rc4-40, rc4-56 che indica gli algoritmi
RC4 rispettivamente con una
chiave a 128, 40 e 56 bit.
·
auth-param
È un campo inutilizzato, previsto per scopi futuri.
Passo
Due
A questo punto il client prende nota del digest challenge e risponde al server con una stringa strutturata
e costruita secondo le regole del digest response definite come segue:
digest-response =
1#( username | realm | nonce | cnonce |
nonce-count | qop | digest-uri | response |
maxbuf | charset | cipher | authzid |auth-param )
username = "username" "=" <"> username-value <">
username-value = qdstr-val
cnonce = "cnonce" "=" <"> cnonce-value <">
cnonce-value = qdstr-val
nonce-count = "nc" "=" nc-value
nc-value = 8LHEX
qop = "qop" "=" qop-value
digest-uri = "digest-uri" "=" <"> digest-uri-value <">
digest-uri-value = serv-type "/" host [ "/" serv-name ]
serv-type = 1*ALPHA
host = 1*( ALPHA | DIGIT | "-" | "." )
serv-name = host
response = "response" "=" response-value
response-value = 32LHEX
LHEX = "0" | "1" | "2" | "3" |
"4" | "5" | "6" | "7" |
"8" | "9" | "a" | "b" |
"c" | "d" | "e" | "f"
cipher = "cipher" "=" cipher-value
authzid = "authzid" "=" <"> authzid-value <">
authzid-value = qdstr-val
Descriviamo ora sinteticamente i campi della struttura:
·
username
È il valore dello username specificato nel campo realm, codificato secondo il valore della direttiva charset.
·
realm
Questo campo contiene l’account dell’utente.
·
nonce
È la stringa specificata dal server nel precedente digest
challenge.
·
cnonce
È una stringa specificata dal cliente che deve essere diversa ad ogni digest response mandata a partire
dalla procedura iniziale di autenticazione. Questo valore è utilizzato dal
client e dal server per evitare attacchi plaintext.
La sicurezza dell’implementazione dipende da una buona scelta di questo
valore.
·
nonce-count
Questo valore è un contatore esadecimale del numero
di richieste che il client ha inviato, inclusa la richiesta corrente. Ad
esempio, nella prima richiesta spedita in risposta ad
un dato valore di nonce, il client manda “nc = 00000001”.
·
qop
Indica quale “qualità di protezione” il client accetta. Se
presente, appare solo la prima volta ed è una delle alternative
del campo qop-options nello schema al passo
precedente. In caso contrario è per default auth.
·
serv-type
Indica il tipo di servizio, ad esempio www indica i servizi web, ftp indica
i servizi di trasferimento file, SMTP
indica il servizio di mail delivery, ecc.
·
host
Questo campo contiene l’host name del DNS
o l’indirizzo IP del servizio richiesto.
·
serv-name
Indica il nome del servizio.
·
digest-uri
Indica il nome principale del servizio al quale il client vuole connettersi,
formato dai campi del serv-type, dell’host e del serv-name. Ad esempio,
il servizio di FTP su ftp.example.com
avrà come valore del digest-uri “ftp/ftp.example.com”.
·
response
È una stringa di 32 cifre esadecimali, che
descriveremo più avanti. Questa stringa prova che l’utente conosce la
password esatta per autenticarsi. Questa direttiva deve
essere necessariamente presente la prima volta, altrimenti l’autenticazione
fallisce.
·
maxbuf
Questo valore indica la dimensione massima del buffer di dati che il client è
capace di gestire. Il valore di default è 65563. Questo campo, inoltre, può apparire solo una volta;
se alle volte successive ci sono altri valori, il server può abortire la
procedura di autenticazione.
·
charset
Questa direttiva, se presente, specifica se il server supporta lo schema di
caratteri UTF-8 per la codifica dello username e
della password.
·
LHEX
E’ un campo di 32 cifre esadecimali, dove i caratteri
alfabetici devono essere necessariamente lower case,
poiché l’algoritmo MD5 è case sensitive.
·
cipher
È l’algoritmo di cifratura scelto dal client. Questa direttiva deve
essere presente solo se viene negoziata
l’opzione auth-conf. Se viene
richiesta e non è presente, l’autenticazione fallisce.
·
authzid
È un campo opzionale, che contiene l’ID per l’autorizzazione.
Ritorniamo al valore del campo response, formato da 32 cifre esadecimali con caratteri lower case. Mostriamo come il valore è calcolato.
response-value =
HEX( KD ( HEX(H(A1)), { nonce-value, ":" nc-value, ":", cnonce-value, ":", qop-value, ":", HEX(H(A2)) }))
Se il campo authzid è
presente, allora A1 è uguale a:
A1 = { H( { username-value, ":",
realm-value, ":", passwd } ),
":", nonce-value, ":", cnonce-value,
":", authzid-value }
Se il campo authzid non è
presente, allora A1 è uguale a:
A1 = { H( { username-value, ":",
realm-value, ":", passwd } ),
":", nonce-value, ":", cnonce-value
}
dove passwd = *OCTET
Se il valore del campo qop è
auth, allora A2 è uguale a:
A2 = { "AUTHENTICATE:", digest-uri-value }
Se il valore del campo qop è auth-int oppure auth-conf allora A2 è:
A2 = { "AUTHENTICATE:",
digest-uri-value,
":00000000000000000000000000000000" }
Passo
Tre
Il server a questo punto riceve e verifica la digest response. Verifica anzitutto che
il valore di nonce-count è “00000001” e
manda un messaggio strutturato come segue:
response-auth = "rspauth" "=" response-value
dove il response-value è calcolato, come descritto al passo precedente, usando i valori mandati al passo due, eccetto che se il valore di qop è auth, allora A2 è:
A2 = { ":", digest-uri-value }
E se qop è auth-int oppure auth-conf allora A2 vale:
A2 = { ":", digest-uri-value, ":00000000000000000000000000000000" }