Skip to content

Commit 98cf950

Browse files
committed
♻️ SASL CRAM-MD5: Add "#done?" [🚧 WIP]
The client should raise an error if the command completes successfully but "done?" returns false. Also moved to sasl dir and SASL module cram move
1 parent 7ed3bd8 commit 98cf950

File tree

4 files changed

+69
-53
lines changed

4 files changed

+69
-53
lines changed

lib/net/imap/authenticators.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,5 +104,5 @@ def authenticators
104104

105105
# deprecated
106106
require_relative "authenticators/login"
107-
require_relative "authenticators/cram_md5"
107+
require_relative "sasl/cram_md5_authenticator"
108108
require_relative "sasl/digest_md5_authenticator"

lib/net/imap/authenticators/cram_md5.rb

Lines changed: 0 additions & 51 deletions
This file was deleted.
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# frozen_string_literal: true
2+
3+
module Net
4+
class IMAP < Protocol
5+
module SASL
6+
7+
# Authenticator for the "+CRAM-MD5+" SASL mechanism, specified in
8+
# RFC2195[https://tools.ietf.org/html/rfc2195]. See Net::IMAP#authenticate.
9+
#
10+
# == Deprecated
11+
#
12+
# +CRAM-MD5+ is obsolete and insecure. It is included for compatibility with
13+
# existing servers.
14+
# {draft-ietf-sasl-crammd5-to-historic}[https://tools.ietf.org/html/draft-ietf-sasl-crammd5-to-historic-00.html]
15+
# recommends using +SCRAM-*+ or +PLAIN+ protected by TLS instead.
16+
#
17+
# Additionally, RFC8314[https://tools.ietf.org/html/rfc8314] discourage the use
18+
# of cleartext and recommends TLS version 1.2 or greater be used for all
19+
# traffic. With TLS +CRAM-MD5+ is okay, but so is +PLAIN+
20+
class CramMD5Authenticator
21+
def process(challenge)
22+
digest = hmac_md5(challenge, @password)
23+
return @user + " " + digest
24+
ensure
25+
@done = true
26+
end
27+
28+
def done?; @done end
29+
30+
private
31+
32+
def initialize(user, password, warn_deprecation: true, **_ignored)
33+
if warn_deprecation
34+
warn "WARNING: CRAM-MD5 mechanism is deprecated." # TODO: recommend SCRAM
35+
end
36+
require "digest/md5"
37+
@user = user
38+
@password = password
39+
@done = false
40+
end
41+
42+
def hmac_md5(text, key)
43+
if key.length > 64
44+
key = Digest::MD5.digest(key)
45+
end
46+
47+
k_ipad = key + "\0" * (64 - key.length)
48+
k_opad = key + "\0" * (64 - key.length)
49+
for i in 0..63
50+
k_ipad[i] = (k_ipad[i].ord ^ 0x36).chr
51+
k_opad[i] = (k_opad[i].ord ^ 0x5c).chr
52+
end
53+
54+
digest = Digest::MD5.digest(k_ipad + text)
55+
56+
return Digest::MD5.hexdigest(k_opad + digest)
57+
end
58+
59+
Net::IMAP.add_authenticator "CRAM-MD5", self
60+
end
61+
end
62+
63+
CramMD5Authenticator = SASL::CramMD5Authenticator
64+
deprecate_constant :CramMD5Authenticator
65+
66+
end
67+
end

test/net/imap/sasl/test_authenticators.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ def cram_md5(*args, warn_deprecation: false, **kwargs, &block)
185185
end
186186

187187
def test_cram_md5_authenticator_matches_mechanism
188-
assert_kind_of(Net::IMAP::CramMD5Authenticator, cram_md5("n", "p"))
188+
assert_kind_of(Net::IMAP::SASL::CramMD5Authenticator, cram_md5("n", "p"))
189189
end
190190

191191
def test_cram_md5_authenticator_deprecated

0 commit comments

Comments
 (0)