github.com/silveraid/fabric-ca@v1.1.0-preview.0.20180127000700-71974f53ab08/lib/util.go (about) 1 /* 2 Copyright IBM Corp. 2016 All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package lib 18 19 import ( 20 "crypto/tls" 21 "crypto/x509" 22 "encoding/hex" 23 "encoding/json" 24 "encoding/pem" 25 "fmt" 26 "io/ioutil" 27 "net/http" 28 "strings" 29 30 "github.com/pkg/errors" 31 32 "github.com/cloudflare/cfssl/log" 33 "github.com/hyperledger/fabric-ca/api" 34 "github.com/hyperledger/fabric-ca/lib/spi" 35 "github.com/hyperledger/fabric-ca/util" 36 "github.com/spf13/viper" 37 ) 38 39 var clientAuthTypes = map[string]tls.ClientAuthType{ 40 "noclientcert": tls.NoClientCert, 41 "requestclientcert": tls.RequestClientCert, 42 "requireanyclientcert": tls.RequireAnyClientCert, 43 "verifyclientcertifgiven": tls.VerifyClientCertIfGiven, 44 "requireandverifyclientcert": tls.RequireAndVerifyClientCert, 45 } 46 47 // GetCertID returns both the serial number and AKI (Authority Key ID) for the certificate 48 func GetCertID(bytes []byte) (string, string, error) { 49 cert, err := BytesToX509Cert(bytes) 50 if err != nil { 51 return "", "", err 52 } 53 serial := util.GetSerialAsHex(cert.SerialNumber) 54 aki := hex.EncodeToString(cert.AuthorityKeyId) 55 return serial, aki, nil 56 } 57 58 // BytesToX509Cert converts bytes (PEM or DER) to an X509 certificate 59 func BytesToX509Cert(bytes []byte) (*x509.Certificate, error) { 60 dcert, _ := pem.Decode(bytes) 61 if dcert != nil { 62 bytes = dcert.Bytes 63 } 64 cert, err := x509.ParseCertificate(bytes) 65 if err != nil { 66 return nil, errors.Wrap(err, "Buffer was neither PEM nor DER encoding") 67 } 68 return cert, err 69 } 70 71 // LoadPEMCertPool loads a pool of PEM certificates from list of files 72 func LoadPEMCertPool(certFiles []string) (*x509.CertPool, error) { 73 certPool := x509.NewCertPool() 74 75 if len(certFiles) > 0 { 76 for _, cert := range certFiles { 77 log.Debugf("Reading cert file: %s", cert) 78 pemCerts, err := ioutil.ReadFile(cert) 79 if err != nil { 80 return nil, err 81 } 82 83 log.Debugf("Appending cert %s to pool", cert) 84 if !certPool.AppendCertsFromPEM(pemCerts) { 85 return nil, errors.New("Failed to load cert pool") 86 } 87 } 88 } 89 90 return certPool, nil 91 } 92 93 // UnmarshalConfig unmarshals a configuration file 94 func UnmarshalConfig(config interface{}, vp *viper.Viper, configFile string, 95 server bool) error { 96 97 vp.SetConfigFile(configFile) 98 err := vp.ReadInConfig() 99 if err != nil { 100 return errors.Wrapf(err, "Failed to read config file '%s'", configFile) 101 } 102 103 err = vp.Unmarshal(config) 104 if err != nil { 105 return errors.Wrapf(err, "Incorrect format in file '%s'", configFile) 106 } 107 if server { 108 serverCfg := config.(*ServerConfig) 109 err = vp.Unmarshal(&serverCfg.CAcfg) 110 if err != nil { 111 return errors.Wrapf(err, "Incorrect format in file '%s'", configFile) 112 } 113 } 114 return nil 115 } 116 117 func getMaxEnrollments(userMaxEnrollments int, caMaxEnrollments int) (int, error) { 118 log.Debugf("Max enrollment value verification - User specified max enrollment: %d, CA max enrollment: %d", userMaxEnrollments, caMaxEnrollments) 119 if userMaxEnrollments < -1 { 120 return 0, errors.Errorf("Max enrollment in registration request may not be less than -1, but was %d", userMaxEnrollments) 121 } 122 switch caMaxEnrollments { 123 case -1: 124 if userMaxEnrollments == 0 { 125 // The user is requesting the matching limit of the CA, so gets infinite 126 return caMaxEnrollments, nil 127 } 128 // There is no CA max enrollment limit, so simply use the user requested value 129 return userMaxEnrollments, nil 130 case 0: 131 // The CA max enrollment is 0, so registration is disabled. 132 return 0, errors.New("Registration is disabled") 133 default: 134 switch userMaxEnrollments { 135 case -1: 136 // User requested infinite enrollments is not allowed 137 return 0, errors.New("Registration for infinite enrollments is not allowed") 138 case 0: 139 // User is requesting the current CA maximum 140 return caMaxEnrollments, nil 141 default: 142 // User is requesting a specific positive value; make sure it doesn't exceed the CA maximum. 143 if userMaxEnrollments > caMaxEnrollments { 144 return 0, errors.Errorf("Requested enrollments (%d) exceeds maximum allowable enrollments (%d)", 145 userMaxEnrollments, caMaxEnrollments) 146 } 147 // otherwise, use the requested maximum 148 return userMaxEnrollments, nil 149 } 150 } 151 } 152 153 // GetUserAffiliation return a joined version version of the affiliation path with '.' as the seperator 154 func GetUserAffiliation(user spi.User) string { 155 return strings.Join(user.GetAffiliationPath(), ".") 156 } 157 158 func addQueryParm(req *http.Request, name, value string) { 159 url := req.URL.Query() 160 url.Add(name, value) 161 req.URL.RawQuery = url.Encode() 162 } 163 164 // IdentityDecoder decodes streams of data coming from the server into an Identity object 165 func IdentityDecoder(decoder *json.Decoder) error { 166 var id api.IdentityInfo 167 err := decoder.Decode(&id) 168 if err != nil { 169 return err 170 } 171 fmt.Printf("Name: %s, Type: %s, Affiliation: %s, Max Enrollments: %d, Attributes: %+v\n", id.ID, id.Type, id.Affiliation, id.MaxEnrollments, id.Attributes) 172 return nil 173 } 174 175 // AffiliationDecoder decodes streams of data coming from the server into an Affiliation object 176 func AffiliationDecoder(decoder *json.Decoder) error { 177 var aff api.AffiliationInfo 178 err := decoder.Decode(&aff) 179 if err != nil { 180 return err 181 } 182 fmt.Printf("%s\n", aff.Name) 183 return nil 184 }