pki.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. package ovpm
  2. import (
  3. "crypto/rand"
  4. "crypto/rsa"
  5. "crypto/x509"
  6. "crypto/x509/pkix"
  7. "encoding/asn1"
  8. //"github.com/Sirupsen/logrus"
  9. "bytes"
  10. "encoding/pem"
  11. "fmt"
  12. "math/big"
  13. "time"
  14. )
  15. // CertHolder encapsulates a public certificate and the corresponding private key.
  16. type CertHolder struct {
  17. Cert string
  18. Key string // Private Key
  19. }
  20. // CA is a special type of CertHolder that also has a CSR in it.
  21. type CA struct {
  22. CertHolder
  23. CSR string
  24. }
  25. // NewCA returns a newly generated CA.
  26. //
  27. // This will generate a public/private RSA keypair and a authority certificate signed by itself.
  28. func NewCA() (*CA, error) {
  29. key, err := rsa.GenerateKey(rand.Reader, CrtKeyLength)
  30. if err != nil {
  31. return nil, fmt.Errorf("private key cannot be created: %s", err)
  32. }
  33. val, err := asn1.Marshal(basicConstraints{true, 0})
  34. if err != nil {
  35. return nil, fmt.Errorf("can not marshal basic constraints: %s", err)
  36. }
  37. names := pkix.Name{CommonName: "CA"}
  38. var csrTemplate = x509.CertificateRequest{
  39. Subject: names,
  40. SignatureAlgorithm: x509.SHA512WithRSA,
  41. ExtraExtensions: []pkix.Extension{
  42. {
  43. Id: asn1.ObjectIdentifier{2, 5, 29, 19},
  44. Value: val,
  45. Critical: true,
  46. },
  47. },
  48. }
  49. csrCertificate, err := x509.CreateCertificateRequest(rand.Reader, &csrTemplate, key)
  50. if err != nil {
  51. return nil, fmt.Errorf("can not create certificate request: %s", err)
  52. }
  53. csr := pem.EncodeToMemory(&pem.Block{
  54. Type: "CERTIFICATE REQUEST", Bytes: csrCertificate,
  55. })
  56. // Serial number
  57. serial, err := rand.Int(rand.Reader, (&big.Int{}).Exp(big.NewInt(2), big.NewInt(159), nil))
  58. if err != nil {
  59. return nil, err
  60. }
  61. now := time.Now()
  62. // Create the request template
  63. template := x509.Certificate{
  64. SerialNumber: serial,
  65. Subject: names,
  66. NotBefore: now.Add(-10 * time.Minute).UTC(),
  67. NotAfter: now.Add(time.Duration(24*365) * time.Hour).UTC(),
  68. BasicConstraintsValid: true,
  69. IsCA: true,
  70. KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign | x509.KeyUsageCRLSign,
  71. //ExtKeyUsage: []x509.ExtKeyUsage{x509.KeyUsageCertSign, x509.ExtKeyUsageClientAuth},
  72. }
  73. // Sign the certificate authority
  74. certificate, err := x509.CreateCertificate(rand.Reader, &template, &template, &key.PublicKey, key)
  75. if err != nil {
  76. return nil, fmt.Errorf("failed to generate certificate error: %s", err)
  77. }
  78. var request bytes.Buffer
  79. var privateKey bytes.Buffer
  80. if err := pem.Encode(&request, &pem.Block{Type: "CERTIFICATE", Bytes: certificate}); err != nil {
  81. return nil, err
  82. }
  83. if err := pem.Encode(&privateKey, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)}); err != nil {
  84. return nil, err
  85. }
  86. return &CA{
  87. CertHolder: CertHolder{
  88. Key: privateKey.String(),
  89. Cert: request.String(),
  90. },
  91. CSR: string(csr),
  92. }, nil
  93. }
  94. // NewServerCertHolder generates a x509 certificate and a key-pair for the server.
  95. func NewServerCertHolder(ca *CA) (*CertHolder, error) {
  96. return newCert("localhost", ca, true)
  97. }
  98. // NewClientCertHolder generates a x509 certificate and a key-pair for the client.
  99. func NewClientCertHolder(username string, ca *CA) (*CertHolder, error) {
  100. return newCert(username, ca, false)
  101. }
  102. // NewCRL takes in a list of certificate serial numbers and a CA then makes a PEM encoded CRL and returns it as a string.
  103. func NewCRL(revokedCertificateSerials []*big.Int, ca *CA) (string, error) {
  104. caCrt, err := readCertFromPEM(ca.Cert)
  105. if err != nil {
  106. return "", err
  107. }
  108. block, _ := pem.Decode([]byte(ca.Key))
  109. if block == nil {
  110. return "", fmt.Errorf("failed to parse ca private key")
  111. }
  112. priv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
  113. if err != nil {
  114. return "", fmt.Errorf("failed to parse ca private key: %s", err)
  115. }
  116. var revokedCertList []pkix.RevokedCertificate
  117. for _, serial := range revokedCertificateSerials {
  118. revokedCert := pkix.RevokedCertificate{
  119. SerialNumber: serial,
  120. RevocationTime: time.Now().UTC(),
  121. }
  122. revokedCertList = append(revokedCertList, revokedCert)
  123. }
  124. crl, err := caCrt.CreateCRL(rand.Reader, priv, revokedCertList, time.Now().UTC(), time.Now().Add(365*24*60*time.Minute).UTC())
  125. if err != nil {
  126. return "", err
  127. }
  128. crlPem := pem.EncodeToMemory(&pem.Block{
  129. Type: "X509 CRL",
  130. Bytes: crl,
  131. })
  132. return string(crlPem[:]), nil
  133. }
  134. func newCert(commonName string, ca *CA, server bool) (*CertHolder, error) {
  135. // Get CA private key
  136. block, _ := pem.Decode([]byte(ca.Key))
  137. if block == nil {
  138. return nil, fmt.Errorf("failed to parse ca private key")
  139. }
  140. caKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
  141. if err != nil {
  142. return nil, fmt.Errorf("failed to parse ca private key: %s", err)
  143. }
  144. caCert, err := readCertFromPEM(ca.Cert)
  145. if err != nil {
  146. return nil, fmt.Errorf("failed to parse ca cert: %v", err)
  147. }
  148. // Create new cert's key
  149. key, err := rsa.GenerateKey(rand.Reader, 2048)
  150. if err != nil {
  151. return nil, fmt.Errorf("private key cannot be created: %s", err)
  152. }
  153. serial, err := rand.Int(rand.Reader, (&big.Int{}).Exp(big.NewInt(2), big.NewInt(159), nil))
  154. if err != nil {
  155. return nil, err
  156. }
  157. tml := x509.Certificate{
  158. NotBefore: time.Now(),
  159. NotAfter: time.Now().AddDate(5, 0, 0),
  160. SerialNumber: serial,
  161. Subject: pkix.Name{
  162. CommonName: commonName,
  163. Organization: []string{"Innovation"},
  164. },
  165. ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
  166. BasicConstraintsValid: true,
  167. }
  168. if server {
  169. tml.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}
  170. }
  171. // Sign with CA's private key
  172. cert, err := x509.CreateCertificate(rand.Reader, &tml, caCert, &key.PublicKey, caKey)
  173. if err != nil {
  174. return nil, fmt.Errorf("certificate cannot be created: %s", err)
  175. }
  176. priKeyPem := pem.EncodeToMemory(&pem.Block{
  177. Type: "RSA PRIVATE KEY",
  178. Bytes: x509.MarshalPKCS1PrivateKey(key),
  179. })
  180. certPem := pem.EncodeToMemory(&pem.Block{
  181. Type: "CERTIFICATE",
  182. Bytes: cert,
  183. })
  184. return &CertHolder{
  185. Key: string(priKeyPem[:]),
  186. Cert: string(certPem[:]),
  187. }, nil
  188. }
  189. type basicConstraints struct {
  190. IsCA bool `asn1:"optional"`
  191. MaxPathLen int `asn1:"optional,default:-1"`
  192. }
  193. func readCertFromPEM(pemCert string) (*x509.Certificate, error) {
  194. block, _ := pem.Decode([]byte(pemCert))
  195. var cert *x509.Certificate
  196. cert, _ = x509.ParseCertificate(block.Bytes)
  197. return cert, nil
  198. }