github.com/adecaro/fabric-ca@v2.0.0-alpha+incompatible/lib/util.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package lib 8 9 import ( 10 "crypto/tls" 11 "crypto/x509" 12 "encoding/hex" 13 "encoding/json" 14 "encoding/pem" 15 "fmt" 16 "io/ioutil" 17 "net/http" 18 "os" 19 "path/filepath" 20 21 "github.com/cloudflare/cfssl/log" 22 "github.com/grantae/certinfo" 23 "github.com/hyperledger/fabric-ca/api" 24 "github.com/hyperledger/fabric-ca/lib/caerrors" 25 "github.com/hyperledger/fabric-ca/util" 26 "github.com/pkg/errors" 27 "github.com/spf13/viper" 28 ) 29 30 var clientAuthTypes = map[string]tls.ClientAuthType{ 31 "noclientcert": tls.NoClientCert, 32 "requestclientcert": tls.RequestClientCert, 33 "requireanyclientcert": tls.RequireAnyClientCert, 34 "verifyclientcertifgiven": tls.VerifyClientCertIfGiven, 35 "requireandverifyclientcert": tls.RequireAndVerifyClientCert, 36 } 37 38 // GetCertID returns both the serial number and AKI (Authority Key ID) for the certificate 39 func GetCertID(bytes []byte) (string, string, error) { 40 cert, err := BytesToX509Cert(bytes) 41 if err != nil { 42 return "", "", err 43 } 44 serial := util.GetSerialAsHex(cert.SerialNumber) 45 aki := hex.EncodeToString(cert.AuthorityKeyId) 46 return serial, aki, nil 47 } 48 49 // BytesToX509Cert converts bytes (PEM or DER) to an X509 certificate 50 func BytesToX509Cert(bytes []byte) (*x509.Certificate, error) { 51 dcert, _ := pem.Decode(bytes) 52 if dcert != nil { 53 bytes = dcert.Bytes 54 } 55 cert, err := x509.ParseCertificate(bytes) 56 if err != nil { 57 return nil, errors.Wrap(err, "Buffer was neither PEM nor DER encoding") 58 } 59 return cert, err 60 } 61 62 // LoadPEMCertPool loads a pool of PEM certificates from list of files 63 func LoadPEMCertPool(certFiles []string) (*x509.CertPool, error) { 64 certPool := x509.NewCertPool() 65 66 if len(certFiles) > 0 { 67 for _, cert := range certFiles { 68 log.Debugf("Reading cert file: %s", cert) 69 pemCerts, err := ioutil.ReadFile(cert) 70 if err != nil { 71 return nil, err 72 } 73 74 log.Debugf("Appending cert %s to pool", cert) 75 if !certPool.AppendCertsFromPEM(pemCerts) { 76 return nil, errors.New("Failed to load cert pool") 77 } 78 } 79 } 80 81 return certPool, nil 82 } 83 84 // UnmarshalConfig unmarshals a configuration file 85 func UnmarshalConfig(config interface{}, vp *viper.Viper, configFile string, 86 server bool) error { 87 88 vp.SetConfigFile(configFile) 89 err := vp.ReadInConfig() 90 if err != nil { 91 return errors.Wrapf(err, "Failed to read config file '%s'", configFile) 92 } 93 94 err = vp.Unmarshal(config) 95 if err != nil { 96 return errors.Wrapf(err, "Incorrect format in file '%s'", configFile) 97 } 98 if server { 99 serverCfg := config.(*ServerConfig) 100 err = vp.Unmarshal(&serverCfg.CAcfg) 101 if err != nil { 102 return errors.Wrapf(err, "Incorrect format in file '%s'", configFile) 103 } 104 } 105 return nil 106 } 107 108 func getMaxEnrollments(userMaxEnrollments int, caMaxEnrollments int) (int, error) { 109 log.Debugf("Max enrollment value verification - User specified max enrollment: %d, CA max enrollment: %d", userMaxEnrollments, caMaxEnrollments) 110 if userMaxEnrollments < -1 { 111 return 0, caerrors.NewHTTPErr(400, caerrors.ErrInvalidMaxEnroll, "Max enrollment in registration request may not be less than -1, but was %d", userMaxEnrollments) 112 } 113 switch caMaxEnrollments { 114 case -1: 115 if userMaxEnrollments == 0 { 116 // The user is requesting the matching limit of the CA, so gets infinite 117 return caMaxEnrollments, nil 118 } 119 // There is no CA max enrollment limit, so simply use the user requested value 120 return userMaxEnrollments, nil 121 case 0: 122 // The CA max enrollment is 0, so registration is disabled. 123 return 0, caerrors.NewHTTPErr(400, caerrors.ErrInvalidMaxEnroll, "Registration is disabled") 124 default: 125 switch userMaxEnrollments { 126 case -1: 127 // User requested infinite enrollments is not allowed 128 return 0, caerrors.NewHTTPErr(400, caerrors.ErrInvalidMaxEnroll, "Registration for infinite enrollments is not allowed") 129 case 0: 130 // User is requesting the current CA maximum 131 return caMaxEnrollments, nil 132 default: 133 // User is requesting a specific positive value; make sure it doesn't exceed the CA maximum. 134 if userMaxEnrollments > caMaxEnrollments { 135 return 0, caerrors.NewHTTPErr(400, caerrors.ErrInvalidMaxEnroll, "Requested enrollments (%d) exceeds maximum allowable enrollments (%d)", userMaxEnrollments, caMaxEnrollments) 136 } 137 // otherwise, use the requested maximum 138 return userMaxEnrollments, nil 139 } 140 } 141 } 142 143 func addQueryParm(req *http.Request, name, value string) { 144 url := req.URL.Query() 145 url.Add(name, value) 146 req.URL.RawQuery = url.Encode() 147 } 148 149 // IdentityDecoder decodes streams of data coming from the server into an Identity object 150 func IdentityDecoder(decoder *json.Decoder) error { 151 var id api.IdentityInfo 152 err := decoder.Decode(&id) 153 if err != nil { 154 return err 155 } 156 fmt.Printf("Name: %s, Type: %s, Affiliation: %s, Max Enrollments: %d, Attributes: %+v\n", id.ID, id.Type, id.Affiliation, id.MaxEnrollments, id.Attributes) 157 return nil 158 } 159 160 // AffiliationDecoder decodes streams of data coming from the server into an Affiliation object 161 func AffiliationDecoder(decoder *json.Decoder) error { 162 var aff api.AffiliationInfo 163 err := decoder.Decode(&aff) 164 if err != nil { 165 return err 166 } 167 fmt.Printf("%s\n", aff.Name) 168 return nil 169 } 170 171 // CertificateDecoder is needed to keep track of state, to see how many certificates 172 // have been returned for each enrollment ID. 173 type CertificateDecoder struct { 174 certIDCount map[string]int 175 storePath string 176 } 177 178 // NewCertificateDecoder returns decoder for certificates 179 func NewCertificateDecoder(storePath string) *CertificateDecoder { 180 cd := &CertificateDecoder{} 181 cd.certIDCount = make(map[string]int) 182 cd.storePath = storePath 183 return cd 184 } 185 186 // CertificateDecoder decodes streams of data coming from the server 187 func (cd *CertificateDecoder) CertificateDecoder(decoder *json.Decoder) error { 188 var cert certPEM 189 err := decoder.Decode(&cert) 190 if err != nil { 191 return err 192 } 193 block, rest := pem.Decode([]byte(cert.PEM)) 194 if block == nil || len(rest) > 0 { 195 return errors.New("Certificate decoding error") 196 } 197 certificate, err := x509.ParseCertificate(block.Bytes) 198 if err != nil { 199 return err 200 } 201 enrollmentID := certificate.Subject.CommonName 202 if cd.storePath != "" { 203 err = cd.StoreCert(enrollmentID, cd.storePath, []byte(cert.PEM)) 204 if err != nil { 205 return err 206 } 207 } 208 209 result, err := certinfo.CertificateText(certificate) 210 if err != nil { 211 return err 212 } 213 fmt.Printf(result) 214 return nil 215 } 216 217 // StoreCert stores the certificate on the file system 218 func (cd *CertificateDecoder) StoreCert(enrollmentID, storePath string, cert []byte) error { 219 cd.certIDCount[enrollmentID] = cd.certIDCount[enrollmentID] + 1 220 221 err := os.MkdirAll(storePath, os.ModePerm) 222 if err != nil { 223 return err 224 } 225 226 var filePath string 227 singleCertName := fmt.Sprintf("%s.pem", enrollmentID) 228 switch cd.certIDCount[enrollmentID] { 229 case 1: // Only one certificate returned, don't need to append number to certificate file name 230 filePath = filepath.Join(storePath, singleCertName) 231 case 2: // Two certificates returned, rename the old certificate to have number at the end 232 err := os.Rename(filepath.Join(storePath, singleCertName), filepath.Join(storePath, fmt.Sprintf("%s-1.pem", enrollmentID))) 233 if err != nil { 234 return errors.WithMessage(err, fmt.Sprintf("Failed to rename certificate: %s", singleCertName)) 235 } 236 filePath = filepath.Join(storePath, fmt.Sprintf("%s-%d.pem", enrollmentID, cd.certIDCount[enrollmentID])) 237 default: 238 filePath = filepath.Join(storePath, fmt.Sprintf("%s-%d.pem", enrollmentID, cd.certIDCount[enrollmentID])) 239 } 240 241 err = ioutil.WriteFile(filePath, cert, 0644) 242 if err != nil { 243 return errors.WithMessage(err, fmt.Sprintf("Failed to store certificate at: %s", storePath)) 244 } 245 246 return nil 247 }