comparison src/ur/openid.ur @ 9:426dd5c88df1

Fixed checking of nonce timestamp range
author Adam Chlipala <adam@chlipala.net>
date Wed, 29 Dec 2010 14:17:27 -0500
parents 870d99055dd1
children 194577b60771
comparison
equal deleted inserted replaced
8:870d99055dd1 9:426dd5c88df1
1 val discoveryExpiry = 3600 1 val discoveryExpiry = 3600
2 val nonceExpiry = 3600 2 val nonceExpiry = 3600
3 val nonceSkew = 3600
3 4
4 task initialize = fn () => OpenidFfi.init 5 task initialize = fn () => OpenidFfi.init
5 6
6 table discoveries : { Identifier : string, Endpoint : string, Expires : time } 7 table discoveries : { Identifier : string, Endpoint : string, Expires : time }
7 PRIMARY KEY Identifier 8 PRIMARY KEY Identifier
220 | Some nonce => 221 | Some nonce =>
221 case timeOfNonce nonce of 222 case timeOfNonce nonce of
222 None => return (Some "Invalid timestamp in nonce") 223 None => return (Some "Invalid timestamp in nonce")
223 | Some tm => 224 | Some tm =>
224 now <- now; 225 now <- now;
225 exp <- return (addSeconds now nonceExpiry); 226 if tm < addSeconds now (-nonceExpiry) then
226 if tm < exp then
227 return (Some "Nonce timestamp is too old") 227 return (Some "Nonce timestamp is too old")
228 else if tm > addSeconds now nonceSkew then
229 return (Some ("Nonce timestamp is too far in the future: " ^ show tm ^ " (from " ^ nonce ^ ")"))
228 else 230 else
229 b <- oneRowE1 (SELECT COUNT( * ) > 0 231 b <- oneRowE1 (SELECT COUNT( * ) > 0
230 FROM nonces 232 FROM nonces
231 WHERE nonces.Endpoint = {[ep]} 233 WHERE nonces.Endpoint = {[ep]}
232 AND nonces.Nonce = {[nonce]}); 234 AND nonces.Nonce = {[nonce]});
233 235
234 if b then 236 if b then
235 return (Some "Duplicate nonce") 237 return (Some "Duplicate nonce")
236 else 238 else
237 debug ("Nonce expires: " ^ show exp);
238 dml (INSERT INTO nonces (Endpoint, Nonce, Expires) 239 dml (INSERT INTO nonces (Endpoint, Nonce, Expires)
239 VALUES ({[ep]}, {[nonce]}, {[exp]})); 240 VALUES ({[ep]}, {[nonce]}, {[addSeconds now nonceExpiry]}));
240 return None 241 return None
241 242
242 fun verifySig os atype key = 243 fun verifySig os atype key =
243 case OpenidFfi.getOutput os "openid.signed" of 244 case OpenidFfi.getOutput os "openid.signed" of
244 None => return (Some "Missing openid.signed in OP response") 245 None => return (Some "Missing openid.signed in OP response")
245 | Some signed => 246 | Some signed =>
246 case OpenidFfi.getOutput os "openid.sig" of 247 case OpenidFfi.getOutput os "openid.sig" of
247 None => return (Some "Missing openid.sig in OP response") 248 None => return (Some "Missing openid.sig in OP response")
248 | Some sign => let 249 | Some sign => let
249 fun gatherNvps signed acc = 250 fun gatherNvps signed required acc =
250 let 251 let
251 val (this, next) = 252 val (this, next) =
252 case String.split signed #"," of 253 case String.split signed #"," of
253 None => (signed, None) 254 None => (signed, None)
254 | Some (this, next) => (this, Some next) 255 | Some (this, next) => (this, Some next)
255 in 256 in
256 case OpenidFfi.getOutput os ("openid." ^ this) of 257 case OpenidFfi.getOutput os ("openid." ^ this) of
257 None => None 258 None => None
258 | Some value => 259 | Some value =>
259 let 260 let
261 val required = List.filter (fn other => other <> this) required
260 val acc = acc ^ this ^ ":" ^ value ^ "\n" 262 val acc = acc ^ this ^ ":" ^ value ^ "\n"
261 in 263 in
262 case next of 264 case next of
263 None => Some acc 265 None => Some (required, acc)
264 | Some next => gatherNvps next acc 266 | Some next => gatherNvps next required acc
265 end 267 end
266 end 268 end
267 in 269 in
268 case gatherNvps signed "" of 270 case gatherNvps signed ("op_endpoint" :: "return_to" :: "response_nonce" :: "assoc_handle" :: "claimed_id" :: "identity" :: []) "" of
269 None => return (Some "openid.signed mentions missing field") 271 None => return (Some "openid.signed mentions missing field")
270 | Some nvps => 272 | Some ([], nvps) =>
271 let 273 let
272 val sign' = case atype of 274 val sign' = case atype of
273 HMAC_SHA256 => OpenidFfi.sha256 key nvps 275 HMAC_SHA256 => OpenidFfi.sha256 key nvps
274 | HMAC_SHA1 => OpenidFfi.sha1 key nvps 276 | HMAC_SHA1 => OpenidFfi.sha1 key nvps
275 in 277 in
276 debug ("Fields: " ^ signed); 278 (*debug ("Fields: " ^ signed);
277 debug ("Nvps: " ^ nvps); 279 debug ("Nvps: " ^ nvps);
278 debug ("Key: " ^ key); 280 debug ("Key: " ^ key);
279 debug ("His: " ^ sign); 281 debug ("His: " ^ sign);
280 debug ("Mine: " ^ sign'); 282 debug ("Mine: " ^ sign');*)
281 if sign' = sign then 283 if sign' = sign then
282 return None 284 return None
283 else 285 else
284 return (Some "Signatures don't match") 286 return (Some "Signatures don't match")
285 end 287 end
288 | Some (left, _) => return (Some ("openid.signed is missing required fields: " ^ show left))
286 end 289 end
287 290
288 fun returnTo (qs : option queryString) = 291 fun returnTo (qs : option queryString) =
289 case qs of 292 case qs of
290 None => error <xml>Empty query string for OpenID callback</xml> 293 None => error <xml>Empty query string for OpenID callback</xml>