github.com/microsoft/moc@v0.17.1/pkg/certs/certificateAuthority.go (about) 1 // Copyright (c) Microsoft Corporation. All rights reserved. 2 // Licensed under the Apache v2.0 license. 3 package certs 4 5 //go:generate mockgen -destination mock/mock_certificateAuthority.go github.com/microsoft/moc/pkg/certs Revocation 6 7 import ( 8 "bytes" 9 "crypto/rand" 10 "crypto/sha256" 11 "crypto/tls" 12 "crypto/x509" 13 "crypto/x509/pkix" 14 "encoding/asn1" 15 "encoding/pem" 16 "math" 17 "math/big" 18 "time" 19 20 "github.com/microsoft/moc/pkg/errors" 21 ) 22 23 var ( 24 // 1.3.6.1.4.1.311.104 subtree is defined for CIA MSK8S 25 oidRenewCertificates = []int{1, 3, 6, 1, 4, 1, 311, 104, 1, 1} 26 oidOriginalCertificate = []int{1, 3, 6, 1, 4, 1, 311, 104, 1, 2} 27 oidRenewCount = []int{1, 3, 6, 1, 4, 1, 311, 104, 1, 3} 28 29 // RFC 5755 30 OidAccessIdentity = []int{1, 3, 6, 1, 5, 5, 7, 10, 2} 31 ) 32 33 type Revocation interface { 34 IsRevoked(cert *x509.Certificate) error 35 } 36 37 type CAConfig struct { 38 RootSigner *tls.Certificate 39 CrossRootCert *x509.Certificate // OPTIONAL 40 AdditionalRoots []*x509.Certificate // OPTIONAL 41 Revocation Revocation // OPTIONAL 42 } 43 44 type CertificateAuthority struct { 45 rootSigner *tls.Certificate 46 rootCert *x509.Certificate 47 crossRootCert *x509.Certificate 48 rootsPool *x509.CertPool 49 revocation Revocation 50 } 51 52 func parseCertsPEM(pemCerts []byte) ([]*x509.Certificate, error) { 53 ok := false 54 certs := []*x509.Certificate{} 55 for len(pemCerts) > 0 { 56 var block *pem.Block 57 block, pemCerts = pem.Decode(pemCerts) 58 if block == nil { 59 break 60 } 61 // Only use PEM "CERTIFICATE" blocks without extra headers 62 if block.Type != "CERTIFICATE" || len(block.Headers) != 0 { 63 continue 64 } 65 66 cert, err := x509.ParseCertificate(block.Bytes) 67 if err != nil { 68 return certs, err 69 } 70 71 certs = append(certs, cert) 72 ok = true 73 } 74 75 if !ok { 76 return certs, errors.Wrapf(errors.InvalidInput, "data does not contain any valid certificates") 77 } 78 return certs, nil 79 } 80 81 // NewCertificateAuthority creates a CertificateAuthority 82 func NewCertificateAuthority(config *CAConfig) (*CertificateAuthority, error) { 83 var err error 84 85 ca := CertificateAuthority{ 86 rootSigner: config.RootSigner, 87 crossRootCert: config.CrossRootCert, 88 revocation: config.Revocation, 89 } 90 91 ca.rootCert = ca.rootSigner.Leaf 92 if ca.rootCert == nil { 93 ca.rootCert, err = x509.ParseCertificate(ca.rootSigner.Certificate[0]) 94 if err != nil { 95 return nil, errors.Wrapf(errors.Failed, "unable to parse rootSigner: %v", err) 96 } 97 } 98 99 ca.rootsPool = x509.NewCertPool() 100 ca.rootsPool.AddCert(ca.rootCert) 101 102 for _, cert := range config.AdditionalRoots { 103 ca.rootsPool.AddCert(cert) 104 } 105 106 return &ca, nil 107 } 108 109 // VerifyClientCertificate verifies rawCerts(ASN encoded) using the CertificateAuthority 110 func (ca *CertificateAuthority) VerifyClientCertificate(rawCerts [][]byte) error { 111 if len(rawCerts) == 0 { 112 return errors.Wrapf(errors.InvalidInput, "Certificate list empty, nothing to verify") 113 } 114 certs := []*x509.Certificate{} 115 for _, rawcert := range rawCerts { 116 cert, err := x509.ParseCertificate(rawcert) 117 if err != nil { 118 return err 119 } 120 certs = append(certs, cert) 121 } 122 // TODO Need more clarification 123 intermediatesPool := x509.NewCertPool() 124 if len(certs) > 1 { 125 for _, cert := range certs[1:] { 126 intermediatesPool.AddCert(cert) 127 } 128 } 129 130 leaf := certs[0] 131 132 // TODO Current Time 133 verifyOptions := x509.VerifyOptions{ 134 Intermediates: intermediatesPool, 135 Roots: ca.rootsPool, 136 KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny}, 137 } 138 139 _, err := leaf.Verify(verifyOptions) 140 141 if err != nil { 142 return errors.Wrapf(err, "unable to verify client certificate %s", leaf.Subject.CommonName) 143 } 144 145 if ca.revocation != nil { 146 if err = ca.revocation.IsRevoked(leaf); err != nil { 147 return errors.Wrapf(err, "certificate is revoked %s", leaf.Subject.CommonName) 148 } 149 } 150 151 return nil 152 } 153 154 // SignRequest signs the CSR using Certificate Authority 155 // if oldCertPem is provided it is validated against CA 156 func (ca *CertificateAuthority) SignRequest(csrPem []byte, oldCertPem []byte, conf *SignConfig) (retCert []byte, err error) { 157 keyUsage := x509.KeyUsageDigitalSignature 158 extKeyUsage := []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth} 159 160 if conf != nil && conf.ServerAuth { 161 keyUsage |= x509.KeyUsageKeyEncipherment 162 extKeyUsage = append(extKeyUsage, x509.ExtKeyUsageServerAuth) 163 } 164 165 if conf != nil && conf.IsCA { 166 keyUsage |= x509.KeyUsageCertSign 167 } 168 169 csr, err := DecodeCertRequestPEM(csrPem) 170 if err != nil { 171 return 172 } 173 var oldCert *x509.Certificate 174 if oldCertPem != nil || len(oldCertPem) != 0 { 175 if err = ca.VerifyClientCertificate([][]byte{oldCertPem}); err != nil { 176 return nil, errors.Wrapf(errors.InvalidInput, "Old certificate verification failed : %v", err) 177 } 178 oldCert, err = DecodeCertPEM(oldCertPem) 179 } 180 err = csr.CheckSignature() 181 if err != nil { 182 return nil, errors.Wrapf(errors.InvalidInput, "Invalid CSR signature: %v", err) 183 } 184 185 serial, err := rand.Int(rand.Reader, new(big.Int).SetInt64(math.MaxInt64)) 186 if err != nil { 187 return nil, err 188 } 189 190 offset := (time.Hour * 24 * 365) 191 accessIdentity := []byte{} 192 isCA := false 193 if conf != nil { 194 offset = conf.Offset 195 accessIdentity = []byte(conf.Identity) 196 isCA = conf.IsCA 197 } 198 now := time.Now().UTC() 199 200 template := x509.Certificate{ 201 SerialNumber: serial, 202 Subject: csr.Subject, 203 NotBefore: now, 204 NotAfter: now.Add(offset), // 1 year 205 KeyUsage: keyUsage, 206 ExtKeyUsage: extKeyUsage, 207 BasicConstraintsValid: true, 208 DNSNames: csr.DNSNames, 209 IPAddresses: csr.IPAddresses, 210 IsCA: isCA, 211 MaxPathLenZero: isCA, // Enable MaxPathLenZero only when is CA 212 } 213 214 csrRenewCertsPEM := []byte{} 215 216 for _, ext := range csr.Extensions { 217 if ext.Id.Equal(oidRenewCertificates) { 218 csrRenewCertsPEM = ext.Value 219 break 220 } 221 } 222 223 if len(csrRenewCertsPEM) != 0 { 224 225 csrRenewCert, err := parseCertsPEM(csrRenewCertsPEM) 226 if err != nil || len(csrRenewCert) < 2 { 227 return nil, errors.Wrapf(errors.InvalidInput, "missing CSR renew certificates") 228 } 229 230 // csrRenewCert[0] is signed by csrRenewCert[1] 231 // csrRenewCert[1] is cert to be renewed 232 // csrRenewCert[2] ... optional intermediate certificates to verify csrRenewCert 233 234 certToRenew := csrRenewCert[1] 235 236 // The certToRenew must also be used as the clientAuthCert 237 if oldCert != nil { 238 if !bytes.Equal(certToRenew.Raw, oldCert.Raw) { 239 return nil, errors.Wrapf(errors.InvalidInput, "certToRenew wasn't used for clientAuthCert") 240 } 241 } 242 243 intermediatesPool := x509.NewCertPool() 244 if len(csrRenewCert) > 2 { 245 for _, cert := range csrRenewCert[2:] { 246 intermediatesPool.AddCert(cert) 247 } 248 } 249 250 verifyOptions := x509.VerifyOptions{ 251 Intermediates: intermediatesPool, 252 Roots: ca.rootsPool, 253 KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny}, 254 } 255 256 _, err = certToRenew.Verify(verifyOptions) 257 if err != nil { 258 if time.Now().After(certToRenew.NotAfter) { 259 return nil, errors.Wrapf(errors.Expired, "unable to verify certificate to be renewed: Certificate Expired: %v", err) 260 } else { 261 return nil, errors.Wrapf(errors.Failed, "unable to verify certificate to be renewed: %v", err) 262 } 263 } 264 265 err = certToRenew.CheckSignature(csrRenewCert[0].SignatureAlgorithm, 266 csrRenewCert[0].RawTBSCertificate, csrRenewCert[0].Signature) 267 if err != nil { 268 return nil, errors.Wrapf(errors.Failed, "unable to verify signature of CSR Key certificate: %v", err) 269 } 270 271 // Check that the public key in the CSR matches the public key in the CSR Key certificate 272 if !bytes.Equal(csr.RawSubjectPublicKeyInfo, csrRenewCert[0].RawSubjectPublicKeyInfo) { 273 return nil, errors.Wrapf(errors.Failed, "public key in CSR and CSR Key certificate don't match") 274 } 275 276 if ca.revocation != nil { 277 if err = ca.revocation.IsRevoked(certToRenew); err != nil { 278 return nil, errors.Wrapf(err, "certificate is revoked") 279 } 280 } 281 282 // We can now use the content from the certificate to be renewed 283 template = *certToRenew 284 285 // Not reusing the serial number. New serial should be generated 286 template.SerialNumber = serial 287 288 // We are using the same validity as the certificate being renewed 289 validity := template.NotAfter.Sub(template.NotBefore) 290 291 template.NotBefore = time.Now() 292 template.NotAfter = template.NotBefore.Add(validity) 293 spkiHash := sha256.Sum256(csr.RawSubjectPublicKeyInfo) 294 template.SubjectKeyId = spkiHash[:] 295 template.AuthorityKeyId = nil 296 template.SignatureAlgorithm = x509.UnknownSignatureAlgorithm 297 298 origCertDER := certToRenew.Raw 299 var renewCount int64 = 0 300 301 for _, ext := range certToRenew.Extensions { 302 if ext.Id.Equal(oidOriginalCertificate) { 303 origCertDER = ext.Value 304 } else if ext.Id.Equal(oidRenewCount) { 305 asn1.Unmarshal(ext.Value, &renewCount) 306 } 307 } 308 309 renewCount++ 310 renewCountDER, _ := asn1.Marshal(renewCount) 311 template.ExtraExtensions = []pkix.Extension{ 312 { 313 Id: oidOriginalCertificate, 314 Critical: false, 315 Value: origCertDER, 316 }, 317 { 318 Id: oidRenewCount, 319 Critical: false, 320 Value: renewCountDER, 321 }, 322 } 323 } 324 template.ExtraExtensions = append(template.ExtraExtensions, pkix.Extension{ 325 Id: OidAccessIdentity, 326 Critical: false, 327 Value: accessIdentity, 328 }) 329 cert, err := x509.CreateCertificate(rand.Reader, &template, ca.rootCert, csr.PublicKey, ca.rootSigner.PrivateKey) 330 if err != nil { 331 return 332 } 333 334 x509Cert, err := x509.ParseCertificate(cert) 335 if err != nil { 336 return 337 } 338 retCert = EncodeCertPEM(x509Cert) 339 return 340 }