github.com/brimstone/sbuca@v0.0.0-20151202175429-8691d9eba5c5/ca/ca.go (about) 1 package ca 2 3 import ( 4 "strconv" 5 "time" 6 //"errors" 7 "crypto/rand" 8 "crypto/x509" 9 gopkix "crypto/x509/pkix" 10 "io/ioutil" 11 "math/big" 12 "os" 13 "strings" 14 15 "github.com/brimstone/sbuca/pkix" 16 ) 17 18 type CA struct { 19 RootDir string 20 CertStore *CertStore 21 Certificate *pkix.Certificate 22 Key *pkix.Key 23 } 24 25 func isPathNotExisted(path string) bool { 26 if _, err := os.Stat(path); os.IsNotExist(err) { 27 return true 28 } 29 return false 30 } 31 32 func NewCA(rootDir string) (*CA, error) { 33 34 // mkdir if needed 35 if isPathNotExisted(rootDir + "/ca") { 36 if err := os.MkdirAll(rootDir+"/ca", 0755); err != nil { 37 return nil, err 38 } 39 } 40 41 if isPathNotExisted(rootDir + "/certs") { 42 if err := os.MkdirAll(rootDir+"/certs", 0755); err != nil { 43 return nil, err 44 } 45 } 46 47 var key *pkix.Key 48 var certificate *pkix.Certificate 49 var err error 50 if isPathNotExisted(rootDir + "/ca/ca.key") { 51 // gen priv key 52 key, err = pkix.NewKey() 53 if err != nil { 54 return nil, err 55 } 56 if err := key.ToPEMFile(rootDir + "/ca/ca.key"); err != nil { 57 return nil, err 58 } 59 60 // gen self-signed cert 61 // should refactor, move to cert.go 62 notBefore := time.Now() 63 notAfter := notBefore.Add(time.Hour * 365 * 24) 64 keyUsage := x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature 65 extKeyUsage := []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth} 66 template := &x509.Certificate{ 67 SerialNumber: big.NewInt(1), 68 Subject: gopkix.Name{ 69 CommonName: "try.sbuca.com", 70 }, 71 NotBefore: notBefore, 72 NotAfter: notAfter, 73 KeyUsage: keyUsage, 74 ExtKeyUsage: extKeyUsage, 75 BasicConstraintsValid: true, 76 } 77 78 derBytes, err := x509.CreateCertificate(rand.Reader, template, template, key.PublicKey, key.PrivateKey) 79 if err != nil { 80 return nil, err 81 } 82 certificate, err = pkix.NewCertificateFromDER(derBytes) 83 if err != nil { 84 return nil, err 85 } 86 if err := certificate.ToPEMFile(rootDir + "/ca/ca.crt"); err != nil { 87 return nil, err 88 } 89 90 } else { 91 92 certificate, err = pkix.NewCertificateFromPEMFile(rootDir + "/ca/ca.crt") 93 if err != nil { 94 return nil, err 95 } 96 key, err = pkix.NewKeyFromPrivateKeyPEMFile(rootDir + "/ca/ca.key") 97 if err != nil { 98 return nil, err 99 } 100 101 } 102 103 if isPathNotExisted(rootDir + "/ca/ca.srl") { 104 ioutil.WriteFile(rootDir+"/ca/ca.srl", []byte("2"), 0644) 105 } 106 107 certStore := NewCertStore(rootDir + "/certs") 108 newCA := &CA{ 109 RootDir: rootDir, 110 CertStore: certStore, 111 Certificate: certificate, 112 Key: key, 113 } 114 115 return newCA, nil 116 } 117 func (ca *CA) GetCertificate(id int64) (*pkix.Certificate, error) { 118 return ca.CertStore.Get(id) 119 } 120 func (ca *CA) PutCertificate(id int64, cert *pkix.Certificate) error { 121 return ca.CertStore.Put(id, cert) 122 } 123 func (ca *CA) GetSerialNumber() (*big.Int, error) { 124 snStr, err := ioutil.ReadFile(ca.RootDir + "/ca/ca.srl") 125 if err != nil { 126 panic(err) 127 } 128 snInt, err := strconv.Atoi(strings.Trim(string(snStr), "\n")) 129 if err != nil { 130 panic(err) 131 } 132 sn := big.NewInt(int64(snInt)) 133 134 return sn, nil 135 } 136 func (ca *CA) IncreaseSerialNumber() error { 137 snStr, err := ioutil.ReadFile(ca.RootDir + "/ca/ca.srl") 138 if err != nil { 139 panic(err) 140 } 141 snInt, err := strconv.Atoi(strings.Trim(string(snStr), "\n")) 142 if err != nil { 143 panic(err) 144 } 145 nextSnInt := snInt + 1 146 nextSnStr := strconv.Itoa(nextSnInt) + "\n" 147 ioutil.WriteFile(ca.RootDir+"/ca/ca.srl", []byte(nextSnStr), 0600) 148 149 return nil 150 } 151 func (ca *CA) IssueCertificate(csr *pkix.CertificateRequest) (*pkix.Certificate, error) { 152 153 serialNumber, err := ca.GetSerialNumber() 154 if err != nil { 155 return nil, err 156 } 157 notBefore := time.Now() 158 notAfter := notBefore.Add(time.Hour * 365 * 24) 159 keyUsage := x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature 160 extKeyUsage := []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth} 161 template := &x509.Certificate{ 162 SerialNumber: serialNumber, 163 Subject: csr.Csr.Subject, 164 NotBefore: notBefore, 165 NotAfter: notAfter, 166 KeyUsage: keyUsage, 167 ExtKeyUsage: extKeyUsage, 168 BasicConstraintsValid: true, 169 } 170 171 derBytes, err := x509.CreateCertificate(rand.Reader, template, ca.Certificate.Crt, ca.Key.PublicKey, ca.Key.PrivateKey) 172 if err != nil { 173 return nil, err 174 } 175 176 // increase sn 177 if err = ca.IncreaseSerialNumber(); err != nil { 178 return nil, err 179 } 180 181 // gen new cert 182 cert, err := pkix.NewCertificateFromDER(derBytes) 183 if err != nil { 184 return nil, err 185 } 186 187 // put in certstore 188 if err = ca.PutCertificate(serialNumber.Int64(), cert); err != nil { 189 return nil, err 190 } 191 192 return cert, nil 193 }