certificate.go 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. //go:build !js
  2. // +build !js
  3. package webrtc
  4. import (
  5. "crypto"
  6. "crypto/ecdsa"
  7. "crypto/rand"
  8. "crypto/rsa"
  9. "crypto/x509"
  10. "crypto/x509/pkix"
  11. "encoding/base64"
  12. "encoding/pem"
  13. "fmt"
  14. "math/big"
  15. "strings"
  16. "time"
  17. "github.com/pion/dtls/v2/pkg/crypto/fingerprint"
  18. "github.com/pion/webrtc/v3/pkg/rtcerr"
  19. )
  20. // Certificate represents a x509Cert used to authenticate WebRTC communications.
  21. type Certificate struct {
  22. privateKey crypto.PrivateKey
  23. x509Cert *x509.Certificate
  24. statsID string
  25. }
  26. // NewCertificate generates a new x509 compliant Certificate to be used
  27. // by DTLS for encrypting data sent over the wire. This method differs from
  28. // GenerateCertificate by allowing to specify a template x509.Certificate to
  29. // be used in order to define certificate parameters.
  30. func NewCertificate(key crypto.PrivateKey, tpl x509.Certificate) (*Certificate, error) {
  31. var err error
  32. var certDER []byte
  33. switch sk := key.(type) {
  34. case *rsa.PrivateKey:
  35. pk := sk.Public()
  36. tpl.SignatureAlgorithm = x509.SHA256WithRSA
  37. certDER, err = x509.CreateCertificate(rand.Reader, &tpl, &tpl, pk, sk)
  38. if err != nil {
  39. return nil, &rtcerr.UnknownError{Err: err}
  40. }
  41. case *ecdsa.PrivateKey:
  42. pk := sk.Public()
  43. tpl.SignatureAlgorithm = x509.ECDSAWithSHA256
  44. certDER, err = x509.CreateCertificate(rand.Reader, &tpl, &tpl, pk, sk)
  45. if err != nil {
  46. return nil, &rtcerr.UnknownError{Err: err}
  47. }
  48. default:
  49. return nil, &rtcerr.NotSupportedError{Err: ErrPrivateKeyType}
  50. }
  51. cert, err := x509.ParseCertificate(certDER)
  52. if err != nil {
  53. return nil, &rtcerr.UnknownError{Err: err}
  54. }
  55. return &Certificate{privateKey: key, x509Cert: cert, statsID: fmt.Sprintf("certificate-%d", time.Now().UnixNano())}, nil
  56. }
  57. // Equals determines if two certificates are identical by comparing both the
  58. // secretKeys and x509Certificates.
  59. func (c Certificate) Equals(o Certificate) bool {
  60. switch cSK := c.privateKey.(type) {
  61. case *rsa.PrivateKey:
  62. if oSK, ok := o.privateKey.(*rsa.PrivateKey); ok {
  63. if cSK.N.Cmp(oSK.N) != 0 {
  64. return false
  65. }
  66. return c.x509Cert.Equal(o.x509Cert)
  67. }
  68. return false
  69. case *ecdsa.PrivateKey:
  70. if oSK, ok := o.privateKey.(*ecdsa.PrivateKey); ok {
  71. if cSK.X.Cmp(oSK.X) != 0 || cSK.Y.Cmp(oSK.Y) != 0 {
  72. return false
  73. }
  74. return c.x509Cert.Equal(o.x509Cert)
  75. }
  76. return false
  77. default:
  78. return false
  79. }
  80. }
  81. // Expires returns the timestamp after which this certificate is no longer valid.
  82. func (c Certificate) Expires() time.Time {
  83. if c.x509Cert == nil {
  84. return time.Time{}
  85. }
  86. return c.x509Cert.NotAfter
  87. }
  88. // GetFingerprints returns the list of certificate fingerprints, one of which
  89. // is computed with the digest algorithm used in the certificate signature.
  90. func (c Certificate) GetFingerprints() ([]DTLSFingerprint, error) {
  91. fingerprintAlgorithms := []crypto.Hash{crypto.SHA256}
  92. res := make([]DTLSFingerprint, len(fingerprintAlgorithms))
  93. i := 0
  94. for _, algo := range fingerprintAlgorithms {
  95. name, err := fingerprint.StringFromHash(algo)
  96. if err != nil {
  97. return nil, fmt.Errorf("%w: %v", ErrFailedToGenerateCertificateFingerprint, err)
  98. }
  99. value, err := fingerprint.Fingerprint(c.x509Cert, algo)
  100. if err != nil {
  101. return nil, fmt.Errorf("%w: %v", ErrFailedToGenerateCertificateFingerprint, err)
  102. }
  103. res[i] = DTLSFingerprint{
  104. Algorithm: name,
  105. Value: value,
  106. }
  107. }
  108. return res[:i+1], nil
  109. }
  110. // GenerateCertificate causes the creation of an X.509 certificate and
  111. // corresponding private key.
  112. func GenerateCertificate(secretKey crypto.PrivateKey) (*Certificate, error) {
  113. // Max random value, a 130-bits integer, i.e 2^130 - 1
  114. maxBigInt := new(big.Int)
  115. /* #nosec */
  116. maxBigInt.Exp(big.NewInt(2), big.NewInt(130), nil).Sub(maxBigInt, big.NewInt(1))
  117. /* #nosec */
  118. serialNumber, err := rand.Int(rand.Reader, maxBigInt)
  119. if err != nil {
  120. return nil, &rtcerr.UnknownError{Err: err}
  121. }
  122. return NewCertificate(secretKey, x509.Certificate{
  123. Issuer: pkix.Name{CommonName: generatedCertificateOrigin},
  124. NotBefore: time.Now().AddDate(0, 0, -1),
  125. NotAfter: time.Now().AddDate(0, 1, -1),
  126. SerialNumber: serialNumber,
  127. Version: 2,
  128. Subject: pkix.Name{CommonName: generatedCertificateOrigin},
  129. })
  130. }
  131. // CertificateFromX509 creates a new WebRTC Certificate from a given PrivateKey and Certificate
  132. //
  133. // This can be used if you want to share a certificate across multiple PeerConnections
  134. func CertificateFromX509(privateKey crypto.PrivateKey, certificate *x509.Certificate) Certificate {
  135. return Certificate{privateKey, certificate, fmt.Sprintf("certificate-%d", time.Now().UnixNano())}
  136. }
  137. func (c Certificate) collectStats(report *statsReportCollector) error {
  138. report.Collecting()
  139. fingerPrintAlgo, err := c.GetFingerprints()
  140. if err != nil {
  141. return err
  142. }
  143. base64Certificate := base64.RawURLEncoding.EncodeToString(c.x509Cert.Raw)
  144. stats := CertificateStats{
  145. Timestamp: statsTimestampFrom(time.Now()),
  146. Type: StatsTypeCertificate,
  147. ID: c.statsID,
  148. Fingerprint: fingerPrintAlgo[0].Value,
  149. FingerprintAlgorithm: fingerPrintAlgo[0].Algorithm,
  150. Base64Certificate: base64Certificate,
  151. IssuerCertificateID: c.x509Cert.Issuer.String(),
  152. }
  153. report.Collect(stats.ID, stats)
  154. return nil
  155. }
  156. // CertificateFromPEM creates a fresh certificate based on a string containing
  157. // pem blocks fort the private key and x509 certificate
  158. func CertificateFromPEM(pems string) (*Certificate, error) {
  159. // decode & parse the certificate
  160. block, more := pem.Decode([]byte(pems))
  161. if block == nil || block.Type != "CERTIFICATE" {
  162. return nil, errCertificatePEMFormatError
  163. }
  164. certBytes := make([]byte, base64.StdEncoding.DecodedLen(len(block.Bytes)))
  165. n, err := base64.StdEncoding.Decode(certBytes, block.Bytes)
  166. if err != nil {
  167. return nil, fmt.Errorf("failed to decode ceritifcate: %w", err)
  168. }
  169. cert, err := x509.ParseCertificate(certBytes[:n])
  170. if err != nil {
  171. return nil, fmt.Errorf("failed parsing ceritifcate: %w", err)
  172. }
  173. // decode & parse the private key
  174. block, _ = pem.Decode(more)
  175. if block == nil || block.Type != "PRIVATE KEY" {
  176. return nil, errCertificatePEMFormatError
  177. }
  178. privateKey, err := x509.ParsePKCS8PrivateKey(block.Bytes)
  179. if err != nil {
  180. return nil, fmt.Errorf("unable to parse private key: %w", err)
  181. }
  182. x := CertificateFromX509(privateKey, cert)
  183. return &x, nil
  184. }
  185. // PEM returns the certificate encoded as two pem block: once for the X509
  186. // certificate and the other for the private key
  187. func (c Certificate) PEM() (string, error) {
  188. // First write the X509 certificate
  189. var o strings.Builder
  190. xcertBytes := make(
  191. []byte, base64.StdEncoding.EncodedLen(len(c.x509Cert.Raw)))
  192. base64.StdEncoding.Encode(xcertBytes, c.x509Cert.Raw)
  193. err := pem.Encode(&o, &pem.Block{Type: "CERTIFICATE", Bytes: xcertBytes})
  194. if err != nil {
  195. return "", fmt.Errorf("failed to pem encode the X certificate: %w", err)
  196. }
  197. // Next write the private key
  198. privBytes, err := x509.MarshalPKCS8PrivateKey(c.privateKey)
  199. if err != nil {
  200. return "", fmt.Errorf("failed to marshal private key: %w", err)
  201. }
  202. err = pem.Encode(&o, &pem.Block{Type: "PRIVATE KEY", Bytes: privBytes})
  203. if err != nil {
  204. return "", fmt.Errorf("failed to encode private key: %w", err)
  205. }
  206. return o.String(), nil
  207. }