Files
webrtc/rtccertificate.go
2018-08-28 01:03:09 -07:00

115 lines
2.8 KiB
Go

package webrtc
import (
"crypto"
"crypto/ecdsa"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"encoding/hex"
"math/big"
"time"
)
// RTCCertificate represents a x509Cert used to authenticate WebRTC communications.
type RTCCertificate struct {
secretKey crypto.PrivateKey
x509Cert *x509.Certificate
}
func NewRTCCertificate(key crypto.PrivateKey, tpl x509.Certificate) (*RTCCertificate, error) {
var err error
var certDER []byte
switch sk := key.(type) {
case *rsa.PrivateKey:
pk := sk.Public()
tpl.SignatureAlgorithm = x509.SHA256WithRSA
certDER, err = x509.CreateCertificate(rand.Reader, &tpl, &tpl, pk, sk)
if err != nil {
return nil, &UnknownError{err}
}
case *ecdsa.PrivateKey:
pk := sk.Public()
tpl.SignatureAlgorithm = x509.ECDSAWithSHA256
certDER, err = x509.CreateCertificate(rand.Reader, &tpl, &tpl, pk, sk)
if err != nil {
return nil, &UnknownError{err}
}
default:
return nil, &NotSupportedError{ErrPrivateKeyType}
}
cert, err := x509.ParseCertificate(certDER)
if err != nil {
return nil, &UnknownError{err}
}
return &RTCCertificate{secretKey: key, x509Cert: cert}, nil
}
// Equals determines if two certificates are identical
func (c RTCCertificate) Equals(o RTCCertificate) bool {
switch cSK := c.secretKey.(type) {
case *rsa.PrivateKey:
if oSK, ok := o.secretKey.(*rsa.PrivateKey); ok {
if cSK.N.Cmp(oSK.N) != 0 {
return false
}
return c.x509Cert.Equal(o.x509Cert)
}
return false
case *ecdsa.PrivateKey:
if oSK, ok := o.secretKey.(*ecdsa.PrivateKey); ok {
if cSK.X.Cmp(oSK.X) != 0 || cSK.Y.Cmp(oSK.Y) != 0 {
return false
}
return c.x509Cert.Equal(o.x509Cert)
}
return false
default:
return false
}
}
func (c RTCCertificate) Expires() time.Time {
if c.x509Cert == nil {
return time.Time{}
}
return c.x509Cert.NotAfter
}
func (c RTCCertificate) GetFingerprints() {
}
func GenerateCertificate(secretKey crypto.PrivateKey) (*RTCCertificate, error) {
origin := make([]byte, 16)
if _, err := rand.Read(origin); err != nil {
return nil, &UnknownError{err}
}
// Max random value, a 130-bits integer, i.e 2^130 - 1
maxBigInt := new(big.Int)
maxBigInt.Exp(big.NewInt(2), big.NewInt(130), nil).Sub(maxBigInt, big.NewInt(1))
serialNumber, err := rand.Int(rand.Reader, maxBigInt)
if err != nil {
return nil, &UnknownError{err}
}
return NewRTCCertificate(secretKey, x509.Certificate{
Version: 2,
SerialNumber: serialNumber,
Subject: pkix.Name{CommonName: hex.EncodeToString(origin)},
IsCA: true,
BasicConstraintsValid: true,
NotBefore: time.Now(),
NotAfter: time.Now().AddDate(0, 1, 0),
ExtKeyUsage: []x509.ExtKeyUsage{
x509.ExtKeyUsageClientAuth,
x509.ExtKeyUsageServerAuth,
},
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
})
}