pki.go 6.8 KB

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