Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. // Copyright (c) 2018 Shivaram Lingamneni <slingamn@cs.stanford.edu>
  2. // released under the MIT license
  3. package utils
  4. import (
  5. "crypto/rand"
  6. "crypto/sha256"
  7. "crypto/subtle"
  8. "crypto/tls"
  9. "crypto/x509"
  10. "encoding/base32"
  11. "encoding/base64"
  12. "encoding/hex"
  13. "errors"
  14. "net"
  15. "strings"
  16. "time"
  17. )
  18. var (
  19. // slingamn's own private b32 alphabet, removing 1, l, o, and 0
  20. B32Encoder = base32.NewEncoding("abcdefghijkmnpqrstuvwxyz23456789").WithPadding(base32.NoPadding)
  21. ErrInvalidCertfp = errors.New("Invalid certfp")
  22. ErrNoPeerCerts = errors.New("No certfp available")
  23. ErrNotTLS = errors.New("Connection is not TLS")
  24. )
  25. const (
  26. SecretTokenLength = 26
  27. )
  28. // generate a secret token that cannot be brute-forced via online attacks
  29. func GenerateSecretToken() string {
  30. // 128 bits of entropy are enough to resist any online attack:
  31. var buf [16]byte
  32. rand.Read(buf[:])
  33. // 26 ASCII characters, should be fine for most purposes
  34. return B32Encoder.EncodeToString(buf[:])
  35. }
  36. // securely check if a supplied token matches a stored token
  37. func SecretTokensMatch(storedToken string, suppliedToken string) bool {
  38. // XXX fix a potential gotcha: if the stored token is uninitialized,
  39. // then nothing should match it, not even supplying an empty token.
  40. if len(storedToken) == 0 {
  41. return false
  42. }
  43. return subtle.ConstantTimeCompare([]byte(storedToken), []byte(suppliedToken)) == 1
  44. }
  45. // generate a 256-bit secret key that can be written into a config file
  46. func GenerateSecretKey() string {
  47. var buf [32]byte
  48. rand.Read(buf[:])
  49. return base64.RawURLEncoding.EncodeToString(buf[:])
  50. }
  51. // Normalize openssl-formatted certfp's to oragono's format
  52. func NormalizeCertfp(certfp string) (result string, err error) {
  53. result = strings.ToLower(strings.Replace(certfp, ":", "", -1))
  54. decoded, err := hex.DecodeString(result)
  55. if err != nil || len(decoded) != 32 {
  56. return "", ErrInvalidCertfp
  57. }
  58. return
  59. }
  60. func GetCertFP(conn net.Conn, handshakeTimeout time.Duration) (fingerprint string, peerCerts []*x509.Certificate, err error) {
  61. tlsConn, isTLS := conn.(*tls.Conn)
  62. if !isTLS {
  63. return "", nil, ErrNotTLS
  64. }
  65. // ensure handshake is performed
  66. tlsConn.SetDeadline(time.Now().Add(handshakeTimeout))
  67. err = tlsConn.Handshake()
  68. tlsConn.SetDeadline(time.Time{})
  69. if err != nil {
  70. return "", nil, err
  71. }
  72. peerCerts = tlsConn.ConnectionState().PeerCertificates
  73. if len(peerCerts) < 1 {
  74. return "", nil, ErrNoPeerCerts
  75. }
  76. rawCert := sha256.Sum256(peerCerts[0].Raw)
  77. fingerprint = hex.EncodeToString(rawCert[:])
  78. return fingerprint, peerCerts, nil
  79. }