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