certificate.go 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. /*
  2. * Copyright (c) 2018, Psiphon Inc.
  3. * All rights reserved.
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. *
  18. */
  19. package common
  20. import (
  21. "crypto/rand"
  22. "crypto/rsa"
  23. "crypto/sha1"
  24. "crypto/sha256"
  25. "crypto/x509"
  26. "crypto/x509/pkix"
  27. "encoding/base64"
  28. "encoding/pem"
  29. "math/big"
  30. "time"
  31. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/errors"
  32. )
  33. // GenerateWebServerCertificate creates a self-signed web server certificate,
  34. // using the specified host name. The host name is used as the subject common
  35. // name and a SAN DNS name.
  36. //
  37. // This is primarily intended for use by MeekServer to generate on-the-fly,
  38. // self-signed TLS certificates for fronted HTTPS mode. In this case, the nature
  39. // of the certificate is non-circumvention; it only has to be acceptable to the
  40. // front CDN making connections to meek.
  41. // The same certificates are used for unfronted HTTPS meek. In this case, the
  42. // certificates may be a fingerprint used to detect Psiphon servers or traffic.
  43. // TODO: more effort to mitigate fingerprinting these certificates.
  44. //
  45. // In addition, GenerateWebServerCertificate is used by GenerateConfig to create
  46. // Psiphon web server certificates for test/example configurations. If these Psiphon
  47. // web server certificates are used in production, the same caveats about
  48. // fingerprints apply.
  49. //
  50. // The verification pin return value is a hash of the certificate public key
  51. // which is compatible with FrontingSpec.VerifyPins, and is intended for use
  52. // in testing.
  53. func GenerateWebServerCertificate(hostname string) (string, string, string, error) {
  54. // Based on https://golang.org/src/crypto/tls/generate_cert.go
  55. // TODO: use other key types: anti-fingerprint by varying params
  56. rsaKey, err := rsa.GenerateKey(rand.Reader, 2048)
  57. if err != nil {
  58. return "", "", "", errors.Trace(err)
  59. }
  60. // Validity period is 1 or 2 years, starting 1 to 6 months ago.
  61. validityPeriodYears := 1
  62. delta, err := rand.Int(rand.Reader, big.NewInt(2))
  63. if err != nil {
  64. return "", "", "", errors.Trace(err)
  65. }
  66. validityPeriodYears += int(delta.Int64())
  67. retroactiveMonths := 1
  68. delta, err = rand.Int(rand.Reader, big.NewInt(6))
  69. if err != nil {
  70. return "", "", "", errors.Trace(err)
  71. }
  72. retroactiveMonths += int(delta.Int64())
  73. notBefore := time.Now().Truncate(time.Hour).UTC().AddDate(0, -retroactiveMonths, 0)
  74. notAfter := notBefore.AddDate(validityPeriodYears, 0, 0)
  75. serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
  76. serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
  77. if err != nil {
  78. return "", "", "", errors.Trace(err)
  79. }
  80. publicKeyBytes, err := x509.MarshalPKIXPublicKey(rsaKey.Public())
  81. if err != nil {
  82. return "", "", "", errors.Trace(err)
  83. }
  84. // as per RFC3280 sec. 4.2.1.2
  85. subjectKeyID := sha1.Sum(publicKeyBytes)
  86. var subject pkix.Name
  87. var dnsNames []string
  88. if hostname != "" {
  89. subject = pkix.Name{CommonName: hostname}
  90. dnsNames = []string{hostname}
  91. }
  92. template := x509.Certificate{
  93. SerialNumber: serialNumber,
  94. Subject: subject,
  95. DNSNames: dnsNames,
  96. NotBefore: notBefore,
  97. NotAfter: notAfter,
  98. KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
  99. ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
  100. BasicConstraintsValid: true,
  101. IsCA: true,
  102. SubjectKeyId: subjectKeyID[:],
  103. MaxPathLen: 1,
  104. Version: 2,
  105. }
  106. derCert, err := x509.CreateCertificate(
  107. rand.Reader,
  108. &template,
  109. &template,
  110. rsaKey.Public(),
  111. rsaKey)
  112. if err != nil {
  113. return "", "", "", errors.Trace(err)
  114. }
  115. cert, err := x509.ParseCertificate(derCert)
  116. if err != nil {
  117. return "", "", "", errors.Trace(err)
  118. }
  119. digest := sha256.Sum256(cert.RawSubjectPublicKeyInfo)
  120. pin := base64.StdEncoding.EncodeToString(digest[:])
  121. webServerCertificate := pem.EncodeToMemory(
  122. &pem.Block{
  123. Type: "CERTIFICATE",
  124. Bytes: derCert,
  125. },
  126. )
  127. webServerPrivateKey := pem.EncodeToMemory(
  128. &pem.Block{
  129. Type: "RSA PRIVATE KEY",
  130. Bytes: x509.MarshalPKCS1PrivateKey(rsaKey),
  131. },
  132. )
  133. return string(webServerCertificate), string(webServerPrivateKey), pin, nil
  134. }
  135. // VerifyServerCertificate and VerifyCertificatePins test coverage provided by
  136. // psiphon/controller_test and psiphon/server/server_test.
  137. // VerifyServerCertificate parses and verifies the provided chain. If
  138. // successful, it returns the verified chains that were built.
  139. func VerifyServerCertificate(
  140. rootCAs *x509.CertPool, rawCerts [][]byte, verifyServerName string) ([][]*x509.Certificate, error) {
  141. // This duplicates the verification logic in utls (and standard crypto/tls).
  142. certs := make([]*x509.Certificate, len(rawCerts))
  143. for i, rawCert := range rawCerts {
  144. cert, err := x509.ParseCertificate(rawCert)
  145. if err != nil {
  146. return nil, errors.Trace(err)
  147. }
  148. certs[i] = cert
  149. }
  150. opts := x509.VerifyOptions{
  151. Roots: rootCAs,
  152. DNSName: verifyServerName,
  153. Intermediates: x509.NewCertPool(),
  154. }
  155. for i, cert := range certs {
  156. if i == 0 {
  157. continue
  158. }
  159. opts.Intermediates.AddCert(cert)
  160. }
  161. verifiedChains, err := certs[0].Verify(opts)
  162. if err != nil {
  163. return nil, errors.Trace(err)
  164. }
  165. return verifiedChains, nil
  166. }
  167. // VerifyCertificatePins checks whether any specified certificate pin -- a
  168. // SHA-256 hash of a certificate public key -- if found in the given
  169. // certificate chain.
  170. func VerifyCertificatePins(pins []string, verifiedChains [][]*x509.Certificate) error {
  171. for _, chain := range verifiedChains {
  172. for _, cert := range chain {
  173. publicKeyDigest := sha256.Sum256(cert.RawSubjectPublicKeyInfo)
  174. expectedPin := base64.StdEncoding.EncodeToString(publicKeyDigest[:])
  175. if Contains(pins, expectedPin) {
  176. // Return success on the first match of any certificate public key to any
  177. // pin.
  178. return nil
  179. }
  180. }
  181. }
  182. return errors.TraceNew("no pin found")
  183. }