auth.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  1. package libcobalt
  2. import (
  3. "crypto/rand"
  4. "crypto/sha512"
  5. "encoding/base64"
  6. "errors"
  7. "fmt"
  8. "io"
  9. "io/ioutil"
  10. "math/big"
  11. "strings"
  12. "github.com/ProtonMail/gopenpgp/crypto"
  13. "github.com/ProtonMail/gopenpgp/helper"
  14. xcrypto "github.com/cruxic/bcrypt"
  15. "notabug.org/apiote/gott"
  16. )
  17. // ModulusPublicKey is the default public key against which modulus is verified
  18. var ModulusPublicKey = `-----BEGIN PGP PUBLIC KEY BLOCK-----
  19. Version: SKS 1.1.6
  20. Comment: Hostname: keyserver.ubuntu.com
  21. mDMEXAHLgxYJKwYBBAHaRw8BAQdAFurWXXwjTemqjD7CXjXVyKf0of7n9CtmL8v9enkzggG0
  22. EnByb3RvbkBzcnAubW9kdWx1c4h3BBAWCgApBQJcAcuDBgsJBwgDAgkQNQWFxOlRjyYEFQgK
  23. AgMWAgECGQECGwMCHgEAAPGRAP9sauJsW12UMnTQUZpsbJb53d0Wv55mZIIiJL2XulpWPQD/
  24. V6NglBd96lZKBmInSXX/kXatSv+y0io+LR8i2+jV+Aa4OARcAcuDEgorBgEEAZdVAQUBAQdA
  25. eJHUz1c9+KfEkSIgcBRE3WuXC4oj5a2/U3oASExGDW4DAQgHiGEEGBYIABMFAlwBy4MJEDUF
  26. hcTpUY8mAhsMAAD/XQD8DxNI6E78meodQI+wLsrKLeHn32iLvUqJbVDhfWSUWO4BAMcm1u02
  27. t4VKw++ttECPt+HUgPUq5pqQWe5Q2cW4TMsE
  28. =b/RG
  29. -----END PGP PUBLIC KEY BLOCK-----`
  30. // HttpError is a type of error which contains HTTP response code and body
  31. type HttpError struct {
  32. statusCode int
  33. body io.Reader
  34. }
  35. // HttpError’s Error returns string <code>: <body>
  36. func (e HttpError) Error() string {
  37. b, _ := ioutil.ReadAll(e.body)
  38. return fmt.Sprintf("%d: %s", e.statusCode, string(b))
  39. }
  40. // NewAccount creates an Account from username
  41. func NewAccount(username string) *Account {
  42. a := &Account{username: username}
  43. return a
  44. }
  45. // GetAuthInfo is the first step of SRP authentication. It gets authentication
  46. // info about user from ProtonMail server and updates the Account
  47. func (a *Account) GetAuthInfo() error {
  48. m := map[string]string{
  49. "ClientID": "Cobalt",
  50. "ClientSecret": "4957cc9a2e0a2a49d02475c9d013478d",
  51. "Username": a.username,
  52. }
  53. info, err := gott.NewResult(m).
  54. Bind(marshalRequest).
  55. Bind(prepareInfoRequest).
  56. Map(setHeaders).
  57. Bind(doRequest).
  58. Bind(checkResponse).
  59. Bind(readResponse).
  60. Bind(unmarshalInfoResponse).
  61. Bind(verifyModulus).
  62. Bind(decodeBytes).
  63. Finish()
  64. if err == nil {
  65. a.authInfo = info.(authInfo)
  66. }
  67. return err
  68. }
  69. // IsTwoFactorNeeded returns true if second factor authentication is set up for
  70. // the user; false otherwise
  71. func (a Account) IsTwoFactorNeeded() bool {
  72. // todo use new map
  73. return a.authInfo.TwoFactorNew["TOTP"] == 1
  74. }
  75. // SetCredentials sets password and TOTP code for this authentication attempt
  76. func (a *Account) SetCredentials(password, totp string) {
  77. a.password = password
  78. a.twoFactor = totp
  79. }
  80. // Authenticate tries to authenticate user with given credentials. It uses the
  81. // pass getter function if private key password is needed
  82. func (a *Account) Authenticate() error {
  83. s := srp{
  84. password: a.password,
  85. a: a.authInfo,
  86. generator: big.NewInt(2),
  87. modulus: convertToBigInt(a.authInfo.modulusBytes),
  88. username: a.username,
  89. sessionKey: a.authInfo.SessionKey,
  90. twoFactor: a.twoFactor,
  91. }
  92. response, err := gott.NewResult(&s).
  93. Bind(makeX).
  94. Map(makeMultiplier).
  95. Bind(makeSecret).
  96. Map(makeEphemeral).
  97. Map(makeU).
  98. Map(makeShared).
  99. Map(makeProofs).
  100. Bind(requestAuth).
  101. Bind(verifyServerProof).
  102. Finish()
  103. if err == nil {
  104. r := response.(authResult)
  105. a.authToken = r.AccessToken
  106. a.refreshToken = r.RefreshToken
  107. a.keyPassword = a.password
  108. a.uid = r.Uid
  109. a.seccondPasswordEnabled = r.PasswordMode != 1
  110. a.authInfo = authInfo{}
  111. a.password = ""
  112. a.twoFactor = ""
  113. }
  114. return err
  115. }
  116. // IsSecondPasswordNeeded returns true if account uses 2 password mode;
  117. // false otherwise
  118. func (a Account) IsSecondPasswordNeeded() bool {
  119. return a.seccondPasswordEnabled
  120. }
  121. // SetSecondPassword sets second password for this Account
  122. func (a *Account) SetSecondPassword(pass string) {
  123. a.keyPassword = pass
  124. }
  125. // Revoke closes the session and revokes authentication token
  126. func (a *Account) Revoke() error {
  127. t := gott.Tuple{nil, *a}
  128. _, err := gott.NewResult(t).
  129. Bind(prepareRevokeRequest).
  130. Map(setHeadersAuthed).
  131. Bind(doRequest).
  132. Bind(checkResponse).
  133. Finish()
  134. if err == nil {
  135. a.authToken = ""
  136. a.uid = ""
  137. a.refreshToken = ""
  138. }
  139. return err
  140. }
  141. // Refresh gets new authentication token using refresh token when sesion has
  142. // expired
  143. func (a *Account) Refresh() error {
  144. m := map[string]interface{}{
  145. "ResponseType": "token",
  146. "ClientID": "demoapp",
  147. "GrantType": "refresh_token",
  148. "RefreshToken": a.refreshToken,
  149. "Uid": a.uid,
  150. "RedirectURI": "http://protonmail.ch",
  151. "State": "random_string",
  152. }
  153. r, err := gott.NewResult(gott.Tuple{m, a.keyPassword}).
  154. Bind(marshalRequest).
  155. Bind(prepareRefreshRequest).
  156. Map(setHeaders).
  157. Bind(doRequest).
  158. Bind(checkResponse).
  159. Bind(readResponse).
  160. Bind(unmarshalRefreshResponse).
  161. Finish()
  162. if err == nil {
  163. x := r.(refreshResponse)
  164. a.authToken = x.AccessToken
  165. a.refreshToken = x.RefreshToken
  166. a.uid = x.Uid
  167. }
  168. return err
  169. }
  170. func verifyModulus(response ...interface{}) (interface{}, error) {
  171. pgp := crypto.GetGopenPGP()
  172. verifyTime := pgp.GetUnixTime()
  173. authInfo := response[0].(authInfo)
  174. armored := authInfo.Modulus
  175. verifiedPlainText, err := helper.VerifyCleartextMessageArmored(ModulusPublicKey, armored, verifyTime)
  176. authInfo.Modulus = verifiedPlainText
  177. return authInfo, err
  178. }
  179. func decodeModulus(info ...interface{}) (interface{}, error) {
  180. encoding := base64.StdEncoding
  181. authInfoCopy := info[0].(authInfo)
  182. modulusBytes, err := encoding.DecodeString(authInfoCopy.Modulus)
  183. authInfoCopy.modulusBytes = modulusBytes
  184. return authInfoCopy, err
  185. }
  186. func decodeServerEphemeral(info ...interface{}) (interface{}, error) {
  187. encoding := base64.StdEncoding
  188. authInfoCopy := info[0].(authInfo)
  189. serverEphemeralBytes, err := encoding.DecodeString(authInfoCopy.ServerEphemeral)
  190. authInfoCopy.serverEphemeralBytes = serverEphemeralBytes
  191. return authInfoCopy, err
  192. }
  193. func decodeSalt(info ...interface{}) (interface{}, error) {
  194. encoding := base64.StdEncoding
  195. authInfoCopy := info[0].(authInfo)
  196. saltBytes, err := encoding.DecodeString(authInfoCopy.Salt)
  197. authInfoCopy.saltBytes = saltBytes
  198. return authInfoCopy, err
  199. }
  200. func decodeBytes(response ...interface{}) (interface{}, error) {
  201. return gott.NewResult(response[0]).
  202. Bind(decodeModulus).
  203. Bind(decodeServerEphemeral).
  204. Bind(decodeSalt).
  205. Finish()
  206. }
  207. func makeX(values ...interface{}) (interface{}, error) {
  208. s := values[0].(*srp)
  209. x, err := gott.NewResult(gott.Tuple{s.password, s.a.saltBytes, s.a.modulusBytes, nil}).
  210. Map(makeFullSalt).
  211. Bind(bcrypt).
  212. Map(replaceBcryptVersion).
  213. Map(appendModulus).
  214. Map(hash).
  215. Map(convertToBig).
  216. Finish()
  217. s.x = x.(*big.Int)
  218. return s, err
  219. }
  220. func makeFullSalt(values ...interface{}) interface{} {
  221. salt := values[1].([]byte)
  222. values[1] = append(salt, "proton"...)
  223. return gott.Tuple(values)
  224. }
  225. func bcrypt(values ...interface{}) (interface{}, error) {
  226. password := values[0].(string)
  227. salt := values[1].([]byte)
  228. hash, err := xcrypto.GenerateFromPasswordAndSalt([]byte(password), salt, 10)
  229. values[3] = hash
  230. return gott.Tuple(values), err
  231. }
  232. func replaceBcryptVersion(values ...interface{}) interface{} {
  233. hash := values[3].([]byte)
  234. values[3] = []byte(strings.Replace(string(hash), "$2a$", "$2y$", 1))
  235. return gott.Tuple(values)
  236. }
  237. func appendModulus(values ...interface{}) interface{} {
  238. hash := values[3].([]byte)
  239. modulus := values[2].([]byte)
  240. return append(hash, modulus...)
  241. }
  242. func hash(values ...interface{}) interface{} {
  243. d := values[0].([]byte)
  244. result0 := sha512.Sum512(append(d, 0))
  245. result1 := sha512.Sum512(append(d, 1))
  246. result2 := sha512.Sum512(append(d, 2))
  247. result3 := sha512.Sum512(append(d, 3))
  248. result01 := append(result0[:], result1[:]...)
  249. result23 := append(result2[:], result3[:]...)
  250. return append(result01, result23...)
  251. }
  252. func convertToBig(bytes ...interface{}) interface{} {
  253. return convertToBigInt(bytes[0].([]byte))
  254. }
  255. func convertToBigInt(bytes []byte) *big.Int {
  256. x := big.NewInt(0)
  257. a := append([]byte{}, bytes...)
  258. for i := len(a)/2 - 1; i >= 0; i-- {
  259. opp := len(a) - 1 - i
  260. a[i], a[opp] = a[opp], a[i]
  261. }
  262. return x.SetBytes(a)
  263. }
  264. func convertToBytes(number *big.Int) []byte {
  265. bytes := number.Bytes()
  266. for i := len(bytes)/2 - 1; i >= 0; i-- {
  267. opp := len(bytes) - 1 - i
  268. bytes[i], bytes[opp] = bytes[opp], bytes[i]
  269. }
  270. for len(bytes) < 256 {
  271. bytes = append(bytes, '\x00')
  272. }
  273. return bytes
  274. }
  275. func makeMultiplier(values ...interface{}) interface{} {
  276. s := values[0].(*srp)
  277. modulusBytes := convertToBytes(s.modulus)
  278. gB := convertToBytes(s.generator)
  279. h := hash(append(gB, modulusBytes...)).([]byte)
  280. m := convertToBigInt(h)
  281. s.multiplier = m.Mod(m, s.modulus)
  282. return s
  283. }
  284. func makeSecret(values ...interface{}) (interface{}, error) {
  285. s := values[0].(*srp)
  286. key := [128]byte{}
  287. _, err := rand.Read(key[:])
  288. s.secret = convertToBigInt(key[:])
  289. return s, err
  290. }
  291. func makeEphemeral(values ...interface{}) interface{} {
  292. s := values[0].(*srp)
  293. ephemeral := big.NewInt(0)
  294. s.ephemeral = convertToBytes(ephemeral.Exp(s.generator, s.secret, s.modulus))
  295. return s
  296. }
  297. func makeU(values ...interface{}) interface{} {
  298. s := values[0].(*srp)
  299. s.u = convertToBigInt(hash(append(s.ephemeral, s.a.serverEphemeralBytes...)).([]byte))
  300. return s
  301. }
  302. func makeShared(values ...interface{}) interface{} {
  303. s := values[0].(*srp)
  304. base := convertToBigInt(s.a.serverEphemeralBytes)
  305. base.Sub(base, s.multiplier.Mul(s.multiplier, s.generator.Exp(s.generator, s.x, s.modulus)))
  306. exponent := s.secret.Add(s.secret, s.u.Mul(s.u, s.x))
  307. s.shared = convertToBytes(base.Exp(base, exponent, s.modulus))
  308. return s
  309. }
  310. func makeProofs(values ...interface{}) interface{} {
  311. s := values[0].(*srp)
  312. encoder := base64.StdEncoding
  313. clientProof := hash(append(append(s.ephemeral, s.a.serverEphemeralBytes...), s.shared...)).([]byte)
  314. serverProof := hash(append(append(s.ephemeral, clientProof...), s.shared...)).([]byte)
  315. s.clientProof = encoder.EncodeToString(clientProof)
  316. s.serverProofExpected = encoder.EncodeToString(serverProof)
  317. return s
  318. }
  319. func requestAuth(values ...interface{}) (interface{}, error) {
  320. s := values[0].(*srp)
  321. m := map[string]interface{}{
  322. "Username": s.username,
  323. "ClientID": "Cobalt",
  324. "ClientSecret": "4957cc9a2e0a2a49d02475c9d013478d",
  325. "ClientEphemeral": base64.StdEncoding.EncodeToString(s.ephemeral),
  326. "ClientProof": s.clientProof,
  327. "SRPSession": s.sessionKey,
  328. "TwoFactorCode": s.twoFactor,
  329. }
  330. response, err := gott.NewResult(m).
  331. Bind(marshalRequest).
  332. Bind(prepareAuthRequest).
  333. Map(setHeaders).
  334. Bind(doRequest).
  335. Bind(checkResponse).
  336. Bind(readResponse).
  337. Bind(unmarshalAuthResponse).
  338. Finish()
  339. r := response.(authResult)
  340. if err != nil {
  341. return "", err
  342. }
  343. return gott.Tuple{r, s.serverProofExpected}, err
  344. }
  345. func verifyServerProof(values ...interface{}) (interface{}, error) {
  346. authInfo := values[0].(authResult)
  347. serverProofExpected := values[1].(string)
  348. if serverProofExpected != authInfo.ServerProof {
  349. return authResult{}, errors.New("Invalid server credentials")
  350. } else {
  351. return authInfo, nil
  352. }
  353. }
  354. type srp struct {
  355. password string
  356. a authInfo
  357. x *big.Int
  358. generator *big.Int
  359. modulus *big.Int
  360. multiplier *big.Int
  361. secret *big.Int
  362. ephemeral []byte
  363. u *big.Int
  364. shared []byte
  365. clientProof string
  366. serverProofExpected string
  367. username string
  368. sessionKey string
  369. twoFactor string
  370. }