github.com/hellobchain/third_party@v0.0.0-20230331131523-deb0478a2e52/hyperledger/fabric/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 "encoding/hex" 12 "errors" 13 "fmt" 14 "github.com/hellobchain/newcryptosm/ecdsa" 15 "io" 16 "io/ioutil" 17 "os" 18 "path/filepath" 19 "strings" 20 "sync" 21 22 "github.com/hellobchain/third_party/hyperledger/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(clone, 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 &symmetryPrivateKey{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 *symmetryPrivateKey: 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 files, _ := ioutil.ReadDir(ks.path) 204 for _, f := range files { 205 if f.IsDir() { 206 continue 207 } 208 209 if f.Size() > (1 << 16) { // 64k, somewhat arbitrary limit, considering even large keys 210 continue 211 } 212 213 raw, err := ioutil.ReadFile(filepath.Join(ks.path, f.Name())) 214 if err != nil { 215 continue 216 } 217 218 key, err := pemToPrivateKey(raw, ks.pwd) 219 if err != nil { 220 continue 221 } 222 223 switch kk := key.(type) { 224 case *ecdsa.PrivateKey: 225 k = &ecdsaPrivateKey{kk} 226 default: 227 continue 228 } 229 230 if !bytes.Equal(k.SKI(), ski) { 231 continue 232 } 233 234 return k, nil 235 } 236 return nil, fmt.Errorf("key with SKI %x not found in %s", ski, ks.path) 237 } 238 239 func (ks *fileBasedKeyStore) getSuffix(alias string) string { 240 files, _ := ioutil.ReadDir(ks.path) 241 for _, f := range files { 242 if strings.HasPrefix(f.Name(), alias) { 243 if strings.HasSuffix(f.Name(), "sk") { 244 return "sk" 245 } 246 if strings.HasSuffix(f.Name(), "pk") { 247 return "pk" 248 } 249 if strings.HasSuffix(f.Name(), "key") { 250 return "key" 251 } 252 break 253 } 254 } 255 return "" 256 } 257 258 func (ks *fileBasedKeyStore) storePrivateKey(alias string, privateKey interface{}) error { 259 rawKey, err := privateKeyToPEM(privateKey, ks.pwd) 260 if err != nil { 261 logger.Errorf("Failed converting private key to PEM [%s]: [%s]", alias, err) 262 return err 263 } 264 265 err = ioutil.WriteFile(ks.getPathForAlias(alias, "sk"), rawKey, 0o600) 266 if err != nil { 267 logger.Errorf("Failed storing private key [%s]: [%s]", alias, err) 268 return err 269 } 270 271 return nil 272 } 273 274 func (ks *fileBasedKeyStore) storePublicKey(alias string, publicKey interface{}) error { 275 rawKey, err := publicKeyToPEM(publicKey, ks.pwd) 276 if err != nil { 277 logger.Errorf("Failed converting public key to PEM [%s]: [%s]", alias, err) 278 return err 279 } 280 281 err = ioutil.WriteFile(ks.getPathForAlias(alias, "pk"), rawKey, 0o600) 282 if err != nil { 283 logger.Errorf("Failed storing private key [%s]: [%s]", alias, err) 284 return err 285 } 286 287 return nil 288 } 289 290 func (ks *fileBasedKeyStore) storeKey(alias string, key []byte) error { 291 pem, err := aesToEncryptedPEM(key, ks.pwd) 292 if err != nil { 293 logger.Errorf("Failed converting key to PEM [%s]: [%s]", alias, err) 294 return err 295 } 296 297 err = ioutil.WriteFile(ks.getPathForAlias(alias, "key"), pem, 0o600) 298 if err != nil { 299 logger.Errorf("Failed storing key [%s]: [%s]", alias, err) 300 return err 301 } 302 303 return nil 304 } 305 306 func (ks *fileBasedKeyStore) loadPrivateKey(alias string) (interface{}, error) { 307 path := ks.getPathForAlias(alias, "sk") 308 logger.Debugf("Loading private key [%s] at [%s]...", alias, path) 309 310 raw, err := ioutil.ReadFile(path) 311 if err != nil { 312 logger.Errorf("Failed loading private key [%s]: [%s].", alias, err.Error()) 313 314 return nil, err 315 } 316 317 privateKey, err := pemToPrivateKey(raw, ks.pwd) 318 if err != nil { 319 logger.Errorf("Failed parsing private key [%s]: [%s].", alias, err.Error()) 320 321 return nil, err 322 } 323 324 return privateKey, nil 325 } 326 327 func (ks *fileBasedKeyStore) loadPublicKey(alias string) (interface{}, error) { 328 path := ks.getPathForAlias(alias, "pk") 329 logger.Debugf("Loading public key [%s] at [%s]...", alias, path) 330 331 raw, err := ioutil.ReadFile(path) 332 if err != nil { 333 logger.Errorf("Failed loading public key [%s]: [%s].", alias, err.Error()) 334 335 return nil, err 336 } 337 338 privateKey, err := pemToPublicKey(raw, ks.pwd) 339 if err != nil { 340 logger.Errorf("Failed parsing private key [%s]: [%s].", alias, err.Error()) 341 342 return nil, err 343 } 344 345 return privateKey, nil 346 } 347 348 func (ks *fileBasedKeyStore) loadKey(alias string) ([]byte, error) { 349 path := ks.getPathForAlias(alias, "key") 350 logger.Debugf("Loading key [%s] at [%s]...", alias, path) 351 352 pem, err := ioutil.ReadFile(path) 353 if err != nil { 354 logger.Errorf("Failed loading key [%s]: [%s].", alias, err.Error()) 355 356 return nil, err 357 } 358 359 key, err := pemToAES(pem, ks.pwd) 360 if err != nil { 361 logger.Errorf("Failed parsing key [%s]: [%s]", alias, err) 362 363 return nil, err 364 } 365 366 return key, nil 367 } 368 369 func (ks *fileBasedKeyStore) createKeyStore() error { 370 // Create keystore directory root if it doesn't exist yet 371 ksPath := ks.path 372 logger.Debugf("Creating KeyStore at [%s]...", ksPath) 373 374 err := os.MkdirAll(ksPath, 0o755) 375 if err != nil { 376 return err 377 } 378 379 logger.Debugf("KeyStore created at [%s].", ksPath) 380 return nil 381 } 382 383 func (ks *fileBasedKeyStore) openKeyStore() error { 384 if ks.isOpen { 385 return nil 386 } 387 ks.isOpen = true 388 logger.Debugf("KeyStore opened at [%s]...done", ks.path) 389 390 return nil 391 } 392 393 func (ks *fileBasedKeyStore) getPathForAlias(alias, suffix string) string { 394 return filepath.Join(ks.path, alias+"_"+suffix) 395 } 396 397 func dirExists(path string) (bool, error) { 398 _, err := os.Stat(path) 399 if err == nil { 400 return true, nil 401 } 402 if os.IsNotExist(err) { 403 return false, nil 404 } 405 return false, err 406 } 407 408 func dirEmpty(path string) (bool, error) { 409 f, err := os.Open(path) 410 if err != nil { 411 return false, err 412 } 413 defer f.Close() 414 415 _, err = f.Readdir(1) 416 if err == io.EOF { 417 return true, nil 418 } 419 return false, err 420 }