github.com/osdi23p228/fabric@v0.0.0-20221218062954-77808885f5db/bccsp/sw/fileks.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package sw 8 9 import ( 10 "bytes" 11 "crypto/ecdsa" 12 "encoding/hex" 13 "errors" 14 "fmt" 15 "io" 16 "io/ioutil" 17 "os" 18 "path/filepath" 19 "strings" 20 "sync" 21 22 "github.com/osdi23p228/fabric/bccsp" 23 ) 24 25 // NewFileBasedKeyStore instantiated a file-based key store at a given position. 26 // The key store can be encrypted if a non-empty password is specified. 27 // It can be also be set as read only. In this case, any store operation 28 // will be forbidden 29 func NewFileBasedKeyStore(pwd []byte, path string, readOnly bool) (bccsp.KeyStore, error) { 30 ks := &fileBasedKeyStore{} 31 return ks, ks.Init(pwd, path, readOnly) 32 } 33 34 // fileBasedKeyStore is a folder-based KeyStore. 35 // Each key is stored in a separated file whose name contains the key's SKI 36 // and flags to identity the key's type. All the keys are stored in 37 // a folder whose path is provided at initialization time. 38 // The KeyStore can be initialized with a password, this password 39 // is used to encrypt and decrypt the files storing the keys. 40 // A KeyStore can be read only to avoid the overwriting of keys. 41 type fileBasedKeyStore struct { 42 path string 43 44 readOnly bool 45 isOpen bool 46 47 pwd []byte 48 49 // Sync 50 m sync.Mutex 51 } 52 53 // Init initializes this KeyStore with a password, a path to a folder 54 // where the keys are stored and a read only flag. 55 // Each key is stored in a separated file whose name contains the key's SKI 56 // and flags to identity the key's type. 57 // If the KeyStore is initialized with a password, this password 58 // is used to encrypt and decrypt the files storing the keys. 59 // The pwd can be nil for non-encrypted KeyStores. If an encrypted 60 // key-store is initialized without a password, then retrieving keys from the 61 // KeyStore will fail. 62 // A KeyStore can be read only to avoid the overwriting of keys. 63 func (ks *fileBasedKeyStore) Init(pwd []byte, path string, readOnly bool) error { 64 // Validate inputs 65 // pwd can be nil 66 67 if len(path) == 0 { 68 return errors.New("an invalid KeyStore path provided. Path cannot be an empty string") 69 } 70 71 ks.m.Lock() 72 defer ks.m.Unlock() 73 74 if ks.isOpen { 75 return errors.New("keystore is already initialized") 76 } 77 78 ks.path = path 79 80 clone := make([]byte, len(pwd)) 81 copy(ks.pwd, pwd) 82 ks.pwd = clone 83 ks.readOnly = readOnly 84 85 exists, err := dirExists(path) 86 if err != nil { 87 return err 88 } 89 if !exists { 90 err = ks.createKeyStore() 91 if err != nil { 92 return err 93 } 94 return ks.openKeyStore() 95 } 96 97 empty, err := dirEmpty(path) 98 if err != nil { 99 return err 100 } 101 if empty { 102 err = ks.createKeyStore() 103 if err != nil { 104 return err 105 } 106 } 107 108 return ks.openKeyStore() 109 } 110 111 // ReadOnly returns true if this KeyStore is read only, false otherwise. 112 // If ReadOnly is true then StoreKey will fail. 113 func (ks *fileBasedKeyStore) ReadOnly() bool { 114 return ks.readOnly 115 } 116 117 // GetKey returns a key object whose SKI is the one passed. 118 func (ks *fileBasedKeyStore) GetKey(ski []byte) (bccsp.Key, error) { 119 // Validate arguments 120 if len(ski) == 0 { 121 return nil, errors.New("invalid SKI. Cannot be of zero length") 122 } 123 124 suffix := ks.getSuffix(hex.EncodeToString(ski)) 125 126 switch suffix { 127 case "key": 128 // Load the key 129 key, err := ks.loadKey(hex.EncodeToString(ski)) 130 if err != nil { 131 return nil, fmt.Errorf("failed loading key [%x] [%s]", ski, err) 132 } 133 134 return &aesPrivateKey{key, false}, nil 135 case "sk": 136 // Load the private key 137 key, err := ks.loadPrivateKey(hex.EncodeToString(ski)) 138 if err != nil { 139 return nil, fmt.Errorf("failed loading secret key [%x] [%s]", ski, err) 140 } 141 142 switch k := key.(type) { 143 case *ecdsa.PrivateKey: 144 return &ecdsaPrivateKey{k}, nil 145 default: 146 return nil, errors.New("secret key type not recognized") 147 } 148 case "pk": 149 // Load the public key 150 key, err := ks.loadPublicKey(hex.EncodeToString(ski)) 151 if err != nil { 152 return nil, fmt.Errorf("failed loading public key [%x] [%s]", ski, err) 153 } 154 155 switch k := key.(type) { 156 case *ecdsa.PublicKey: 157 return &ecdsaPublicKey{k}, nil 158 default: 159 return nil, errors.New("public key type not recognized") 160 } 161 default: 162 return ks.searchKeystoreForSKI(ski) 163 } 164 } 165 166 // StoreKey stores the key k in this KeyStore. 167 // If this KeyStore is read only then the method will fail. 168 func (ks *fileBasedKeyStore) StoreKey(k bccsp.Key) (err error) { 169 if ks.readOnly { 170 return errors.New("read only KeyStore") 171 } 172 173 if k == nil { 174 return errors.New("invalid key. It must be different from nil") 175 } 176 switch kk := k.(type) { 177 case *ecdsaPrivateKey: 178 err = ks.storePrivateKey(hex.EncodeToString(k.SKI()), kk.privKey) 179 if err != nil { 180 return fmt.Errorf("failed storing ECDSA private key [%s]", err) 181 } 182 183 case *ecdsaPublicKey: 184 err = ks.storePublicKey(hex.EncodeToString(k.SKI()), kk.pubKey) 185 if err != nil { 186 return fmt.Errorf("failed storing ECDSA public key [%s]", err) 187 } 188 189 case *aesPrivateKey: 190 err = ks.storeKey(hex.EncodeToString(k.SKI()), kk.privKey) 191 if err != nil { 192 return fmt.Errorf("failed storing AES key [%s]", err) 193 } 194 195 default: 196 return fmt.Errorf("key type not reconigned [%s]", k) 197 } 198 199 return 200 } 201 202 func (ks *fileBasedKeyStore) searchKeystoreForSKI(ski []byte) (k bccsp.Key, err error) { 203 204 files, _ := ioutil.ReadDir(ks.path) 205 for _, f := range files { 206 if f.IsDir() { 207 continue 208 } 209 210 if f.Size() > (1 << 16) { //64k, somewhat arbitrary limit, considering even large keys 211 continue 212 } 213 214 raw, err := ioutil.ReadFile(filepath.Join(ks.path, f.Name())) 215 if err != nil { 216 continue 217 } 218 219 key, err := pemToPrivateKey(raw, ks.pwd) 220 if err != nil { 221 continue 222 } 223 224 switch kk := key.(type) { 225 case *ecdsa.PrivateKey: 226 k = &ecdsaPrivateKey{kk} 227 default: 228 continue 229 } 230 231 if !bytes.Equal(k.SKI(), ski) { 232 continue 233 } 234 235 return k, nil 236 } 237 return nil, fmt.Errorf("key with SKI %x not found in %s", ski, ks.path) 238 } 239 240 func (ks *fileBasedKeyStore) getSuffix(alias string) string { 241 files, _ := ioutil.ReadDir(ks.path) 242 for _, f := range files { 243 if strings.HasPrefix(f.Name(), alias) { 244 if strings.HasSuffix(f.Name(), "sk") { 245 return "sk" 246 } 247 if strings.HasSuffix(f.Name(), "pk") { 248 return "pk" 249 } 250 if strings.HasSuffix(f.Name(), "key") { 251 return "key" 252 } 253 break 254 } 255 } 256 return "" 257 } 258 259 func (ks *fileBasedKeyStore) storePrivateKey(alias string, privateKey interface{}) error { 260 rawKey, err := privateKeyToPEM(privateKey, ks.pwd) 261 if err != nil { 262 logger.Errorf("Failed converting private key to PEM [%s]: [%s]", alias, err) 263 return err 264 } 265 266 err = ioutil.WriteFile(ks.getPathForAlias(alias, "sk"), rawKey, 0600) 267 if err != nil { 268 logger.Errorf("Failed storing private key [%s]: [%s]", alias, err) 269 return err 270 } 271 272 return nil 273 } 274 275 func (ks *fileBasedKeyStore) storePublicKey(alias string, publicKey interface{}) error { 276 rawKey, err := publicKeyToPEM(publicKey, ks.pwd) 277 if err != nil { 278 logger.Errorf("Failed converting public key to PEM [%s]: [%s]", alias, err) 279 return err 280 } 281 282 err = ioutil.WriteFile(ks.getPathForAlias(alias, "pk"), rawKey, 0600) 283 if err != nil { 284 logger.Errorf("Failed storing private key [%s]: [%s]", alias, err) 285 return err 286 } 287 288 return nil 289 } 290 291 func (ks *fileBasedKeyStore) storeKey(alias string, key []byte) error { 292 pem, err := aesToEncryptedPEM(key, ks.pwd) 293 if err != nil { 294 logger.Errorf("Failed converting key to PEM [%s]: [%s]", alias, err) 295 return err 296 } 297 298 err = ioutil.WriteFile(ks.getPathForAlias(alias, "key"), pem, 0600) 299 if err != nil { 300 logger.Errorf("Failed storing key [%s]: [%s]", alias, err) 301 return err 302 } 303 304 return nil 305 } 306 307 func (ks *fileBasedKeyStore) loadPrivateKey(alias string) (interface{}, error) { 308 path := ks.getPathForAlias(alias, "sk") 309 logger.Debugf("Loading private key [%s] at [%s]...", alias, path) 310 311 raw, err := ioutil.ReadFile(path) 312 if err != nil { 313 logger.Errorf("Failed loading private key [%s]: [%s].", alias, err.Error()) 314 315 return nil, err 316 } 317 318 privateKey, err := pemToPrivateKey(raw, ks.pwd) 319 if err != nil { 320 logger.Errorf("Failed parsing private key [%s]: [%s].", alias, err.Error()) 321 322 return nil, err 323 } 324 325 return privateKey, nil 326 } 327 328 func (ks *fileBasedKeyStore) loadPublicKey(alias string) (interface{}, error) { 329 path := ks.getPathForAlias(alias, "pk") 330 logger.Debugf("Loading public key [%s] at [%s]...", alias, path) 331 332 raw, err := ioutil.ReadFile(path) 333 if err != nil { 334 logger.Errorf("Failed loading public key [%s]: [%s].", alias, err.Error()) 335 336 return nil, err 337 } 338 339 privateKey, err := pemToPublicKey(raw, ks.pwd) 340 if err != nil { 341 logger.Errorf("Failed parsing private key [%s]: [%s].", alias, err.Error()) 342 343 return nil, err 344 } 345 346 return privateKey, nil 347 } 348 349 func (ks *fileBasedKeyStore) loadKey(alias string) ([]byte, error) { 350 path := ks.getPathForAlias(alias, "key") 351 logger.Debugf("Loading key [%s] at [%s]...", alias, path) 352 353 pem, err := ioutil.ReadFile(path) 354 if err != nil { 355 logger.Errorf("Failed loading key [%s]: [%s].", alias, err.Error()) 356 357 return nil, err 358 } 359 360 key, err := pemToAES(pem, ks.pwd) 361 if err != nil { 362 logger.Errorf("Failed parsing key [%s]: [%s]", alias, err) 363 364 return nil, err 365 } 366 367 return key, nil 368 } 369 370 func (ks *fileBasedKeyStore) createKeyStore() error { 371 // Create keystore directory root if it doesn't exist yet 372 ksPath := ks.path 373 logger.Debugf("Creating KeyStore at [%s]...", ksPath) 374 375 err := os.MkdirAll(ksPath, 0755) 376 if err != nil { 377 return err 378 } 379 380 logger.Debugf("KeyStore created at [%s].", ksPath) 381 return nil 382 } 383 384 func (ks *fileBasedKeyStore) openKeyStore() error { 385 if ks.isOpen { 386 return nil 387 } 388 ks.isOpen = true 389 logger.Debugf("KeyStore opened at [%s]...done", ks.path) 390 391 return nil 392 } 393 394 func (ks *fileBasedKeyStore) getPathForAlias(alias, suffix string) string { 395 return filepath.Join(ks.path, alias+"_"+suffix) 396 } 397 398 func dirExists(path string) (bool, error) { 399 _, err := os.Stat(path) 400 if err == nil { 401 return true, nil 402 } 403 if os.IsNotExist(err) { 404 return false, nil 405 } 406 return false, err 407 } 408 409 func dirEmpty(path string) (bool, error) { 410 f, err := os.Open(path) 411 if err != nil { 412 return false, err 413 } 414 defer f.Close() 415 416 _, err = f.Readdir(1) 417 if err == io.EOF { 418 return true, nil 419 } 420 return false, err 421 }