func TestProcessPrivateKeyFile_encrypted(t *testing.T) { // Encrypt the file b, err := x509.EncryptPEMBlock(rand.Reader, "RSA PRIVATE KEY", []byte("what"), []byte("password"), x509.PEMCipherAES128) if err != nil { t.Fatalf("err: %s", err) } tf, err := ioutil.TempFile("", "packer") if err != nil { t.Fatalf("bad: %s", err) } defer os.Remove(tf.Name()) err = pem.Encode(tf, b) tf.Close() if err != nil { t.Fatalf("err: %s", err) } path := tf.Name() // Should have an error with a bad password if _, err := processPrivateKeyFile(path, "bad"); err == nil { t.Fatal("should error") } if _, err := processPrivateKeyFile(path, "password"); err != nil { t.Fatalf("bad: %s", err) } }
func readKeyOrGenerate(path, pass string) (*rsa.PrivateKey, error) { file, err := ioutil.ReadFile(path) var key *rsa.PrivateKey if err != nil { log.Printf("Generating new key %s...", path) key, err = rsa.GenerateKey(rand.Reader, rsaBitLength) if err != nil { return nil, err } raw := x509.MarshalPKCS1PrivateKey(key) block, err := x509.EncryptPEMBlock(rand.Reader, blockType, raw, []byte(pass), cipherType) if err != nil { return nil, err } encoded := pem.EncodeToMemory(block) ioutil.WriteFile(path, encoded, 0400) } else { log.Printf("Loading key %s...", path) block, _ := pem.Decode(file) if block == nil { return nil, fmt.Errorf("%s doesn't contain a PEM key", path) } raw, err := x509.DecryptPEMBlock(block, []byte(pass)) if err != nil { return nil, err } key, err = x509.ParsePKCS1PrivateKey(raw) if err != nil { return nil, err } } return key, nil }
// PrivateKeyToEncryptedPEM converts a private key to an encrypted PEM func PrivateKeyToEncryptedPEM(privateKey interface{}, pwd []byte) ([]byte, error) { switch k := privateKey.(type) { case *ecdsa.PrivateKey: if k == nil { return nil, errors.New("Invalid ecdsa private key. It must be different from nil.") } raw, err := x509.MarshalECPrivateKey(k) if err != nil { return nil, err } block, err := x509.EncryptPEMBlock( rand.Reader, "ECDSA PRIVATE KEY", raw, pwd, x509.PEMCipherAES256) if err != nil { return nil, err } return pem.EncodeToMemory(block), nil default: return nil, errors.New("Invalid key type. It must be *ecdsa.PrivateKey") } }
func FuzzPEM(data []byte) int { var b pem.Block err := gob.NewDecoder(bytes.NewReader(data)).Decode(&b) if err != nil { return 0 } b1, err := x509.DecryptPEMBlock(&b, []byte("pass")) if err != nil { return 0 } b2, err := x509.EncryptPEMBlock(zeroReader(0), "msg", b1, []byte("pass1"), x509.PEMCipherDES) if err != nil { panic(err) } _, err = x509.DecryptPEMBlock(b2, []byte("pass")) if err == nil { panic("decoded with a wrong pass") } b3, err := x509.DecryptPEMBlock(b2, []byte("pass1")) if err != nil { panic(err) } if !bytes.Equal(b1, b3) { panic("data changed") } return 1 }
// PrivateKeyToEncryptedPEM converts a private key to an encrypted PEM func PrivateKeyToEncryptedPEM(privateKey interface{}, pwd []byte) ([]byte, error) { switch x := privateKey.(type) { case *ecdsa.PrivateKey: raw, err := x509.MarshalECPrivateKey(x) if err != nil { return nil, err } block, err := x509.EncryptPEMBlock( rand.Reader, "ECDSA PRIVATE KEY", raw, pwd, x509.PEMCipherAES256) if err != nil { return nil, err } return pem.EncodeToMemory(block), nil default: return nil, ErrInvalidKey } }
// writeKey takes an unencrypted keyblock and, if the kek is not nil, encrypts it before // writing it to disk. If the kek is nil, writes it to disk unencrypted. func (k *KeyReadWriter) writeKey(keyBlock *pem.Block, kekData KEKData, pkh PEMKeyHeaders) error { if kekData.KEK != nil { encryptedPEMBlock, err := x509.EncryptPEMBlock(rand.Reader, keyBlock.Type, keyBlock.Bytes, kekData.KEK, x509.PEMCipherAES256) if err != nil { return err } if encryptedPEMBlock.Headers == nil { return errors.New("unable to encrypt key - invalid PEM file produced") } keyBlock = encryptedPEMBlock } if pkh != nil { headers, err := pkh.MarshalHeaders(kekData) if err != nil { return err } mergePEMHeaders(keyBlock.Headers, headers) } keyBlock.Headers[versionHeader] = strconv.FormatUint(kekData.Version, 10) if err := ioutils.AtomicWriteFile(k.paths.Key, pem.EncodeToMemory(keyBlock), keyPerms); err != nil { return err } k.kekData = kekData k.headersObj = pkh return nil }
// EncryptPrivateKey returns an encrypted PEM key given a Privatekey // and a passphrase func EncryptPrivateKey(key data.PrivateKey, role, passphrase string) ([]byte, error) { bt, err := blockType(key) if err != nil { return nil, err } password := []byte(passphrase) cipherType := x509.PEMCipherAES256 encryptedPEMBlock, err := x509.EncryptPEMBlock(rand.Reader, bt, key.Private(), password, cipherType) if err != nil { return nil, err } if encryptedPEMBlock.Headers == nil { return nil, fmt.Errorf("unable to encrypt key - invalid PEM file produced") } encryptedPEMBlock.Headers["role"] = role return pem.EncodeToMemory(encryptedPEMBlock), nil }
func EncodePEM(binary []byte, blockType string, password string) (pemBlock string, err error) { var blk *pem.Block /* Awaiting Go 1.1 */ if password != "" { passwordBytes := ([]byte)(password) blk, err = x509.EncryptPEMBlock(rand.Reader, blockType, binary, passwordBytes, x509.PEMCipherAES256) if err != nil { return } } else { /* */ blk = new(pem.Block) blk.Type = blockType blk.Bytes = binary /* Awaiting Go 1.1 */ } /* */ buf := new(bytes.Buffer) err = pem.Encode(buf, blk) if err != nil { return } pemBlock = buf.String() return }
// EncryptPrivateKey returns an encrypted PEM key given a Privatekey // and a passphrase func EncryptPrivateKey(key *data.PrivateKey, passphrase string) ([]byte, error) { var blockType string algorithm := key.Algorithm() switch algorithm { case data.RSAKey: blockType = "RSA PRIVATE KEY" case data.ECDSAKey: blockType = "EC PRIVATE KEY" default: return nil, fmt.Errorf("only RSA or ECDSA keys are currently supported. Found: %s", algorithm) } password := []byte(passphrase) cipherType := x509.PEMCipherAES256 encryptedPEMBlock, err := x509.EncryptPEMBlock(rand.Reader, blockType, key.Private(), password, cipherType) if err != nil { return nil, err } return pem.EncodeToMemory(encryptedPEMBlock), nil }
// EncryptECPrivateKey receives a PEM encoded private key and returns an encrypted // AES256 version using a passphrase // TODO: Make this method generic to handle RSA keys func EncryptECPrivateKey(key []byte, passphraseStr string) ([]byte, error) { passphrase := []byte(passphraseStr) cipherType := x509.PEMCipherAES256 keyBlock, _ := pem.Decode(key) if keyBlock == nil { // This RootCA does not have a valid signer. return nil, fmt.Errorf("error while decoding PEM key") } encryptedPEMBlock, err := x509.EncryptPEMBlock(rand.Reader, "EC PRIVATE KEY", keyBlock.Bytes, passphrase, cipherType) if err != nil { return nil, err } if encryptedPEMBlock.Headers == nil { return nil, fmt.Errorf("unable to encrypt key - invalid PEM file produced") } return pem.EncodeToMemory(encryptedPEMBlock), nil }
// export private key to pem format func exportPrivateKeytoEncryptedPEM(sec *rsa.PrivateKey, password []byte) []byte { l := x509.MarshalPKCS1PrivateKey(sec) m, _ := x509.EncryptPEMBlock(rand.Reader, "RSA PRIVATE KEY", l, password, x509.PEMCipherAES256) n := pem.EncodeToMemory(m) //log.Print(string(n)) return n }
func (ck *RSACertKey) EncPemKey(passwd []byte) ([]byte, error) { //kpem := ck.PemKey() kpem := x509.MarshalPKCS1PrivateKey(ck.key) encblock, err := x509.EncryptPEMBlock(rand.Reader, "RSA PRIVATE KEY", kpem, passwd, x509.PEMCipherAES128) if err != nil { return nil, err } return pem.EncodeToMemory(encblock), nil }
func (ck *ECCertKey) EncPkg(passwd string) ([]byte, error) { var pkgpem []byte pkgpem = append(pkgpem, ck.PemKey()...) pkgpem = append(pkgpem, ck.PemCert()...) encblock, err := x509.EncryptPEMBlock(rand.Reader, pkgTypeStr, pkgpem, []byte(passwd), x509.PEMCipherAES128) if err != nil { return nil, err } return pem.EncodeToMemory(encblock), nil }
// export private key to pem format func exportPrivateKeytoEncryptedPEM(sec *ecdsa.PrivateKey, password []byte) []byte { l, _ := x509.MarshalECPrivateKey(sec) m, _ := x509.EncryptPEMBlock(rand.Reader, "EC PRIVATE KEY", l, password, x509.PEMCipherAES256) n := pem.EncodeToMemory(m) //log.Print(string(n)) keypem, _ := os.OpenFile("sec.Encrypted.pem", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) pem.Encode(keypem, &pem.Block{Type: "EC PRIVATE KEY", Bytes: l}) return n }
func _generateKey(passpharse []byte, config ConfigType) (pubBlock, priBlock *pem.Block, err error) { encodepasspharse := _passpharseHash(passpharse, config.Way) pri, err := rsa.GenerateKey(rand.Reader, config.KeyLength) if err != nil { return } //public key encoding pubbyte, err := x509.MarshalPKIXPublicKey(pri.Public()) if err != nil { return } pubBlock, err = x509.EncryptPEMBlock(rand.Reader, "RSA PUBLIC KEY", pubbyte, []byte{}, x509.PEMCipherAES256) if err != nil { return } //private key encoding pribyte := x509.MarshalPKCS1PrivateKey(pri) priBlock, err = x509.EncryptPEMBlock(rand.Reader, "RSA PRIVATE KEY", pribyte, encodepasspharse, x509.PEMCipherAES256) return }
// AEStoEncryptedPEM encapsulates an AES key in the encrypted PEM format func AEStoEncryptedPEM(raw []byte, pwd []byte) ([]byte, error) { block, err := x509.EncryptPEMBlock( rand.Reader, "AES PRIVATE KEY", raw, pwd, x509.PEMCipherAES256) if err != nil { return nil, err } return pem.EncodeToMemory(block), nil }
func GenerateECDSAKeyPair(keysize int, password string) (public, private []byte, err error) { var curve elliptic.Curve switch keysize { case 256: curve = elliptic.P256() case 384: curve = elliptic.P384() case 521: curve = elliptic.P521() default: return } // Generate the public/private key pair prvKey, err := ecdsa.GenerateKey(curve, rand.Reader) if err != nil { return } // Marshal the public key sshPubKey, err := ssh.NewPublicKey(&prvKey.PublicKey) if err != nil { return } public = ssh.MarshalAuthorizedKey(sshPubKey) // Marshal the private key prvKeyDer, err := x509.MarshalECPrivateKey(prvKey) if err != nil { return } block := &pem.Block{Type: "EC PRIVATE KEY", Bytes: prvKeyDer} // Encrypt the private key if len(password) != 0 { // AES-128 is the only option for private key encryption just like in ssh-keygen. block, err = x509.EncryptPEMBlock(rand.Reader, "EC PRIVATE KEY", prvKeyDer, []byte(password), x509.PEMCipherAES128) if err != nil { return } } private = pem.EncodeToMemory(block) return }
func main() { secretMsg, err := ioutil.ReadFile("cert2.pem") if err != nil { fmt.Printf("ReadFile: %s\n", err) os.Exit(1) } blockType := "ENCRYPTED PRIVATE KEY" password := []byte("password") // see http://golang.org/pkg/crypto/x509/#pkg-constants cipherType := x509.PEMCipherAES128 EncryptedPEMBlock, err := x509.EncryptPEMBlock(rand.Reader, blockType, []byte(secretMsg), password, cipherType) if err != nil { fmt.Println(err) os.Exit(1) } sDec := base64.StdEncoding.EncodeToString(EncryptedPEMBlock.Bytes) bs := len(sDec) // fmt.Printf("raw[%d]:\n%q\n", bs, sDec) fmt.Printf("-----BEGIN %s-----\n", blockType) for k, v := range EncryptedPEMBlock.Headers { fmt.Printf("%s: %s\n", k, v) } fmt.Printf("\n") nblks := bs / 64 rem := bs % 64 // fmt.Printf("nBlks = %d, rem = %d\n", nblks, rem) for i := 0; i < nblks; i++ { fmt.Printf("%s\n", sDec[i*64:(i+1)*64]) } // write the remaining bs-((nblks)*64) fmt.Printf("%s\n", sDec[bs-rem:]) fmt.Printf("-----END %s-----\n", blockType) }
func (crtkit *CertKit) GenerateClient(subject pkix.Name, email, password string) ([]byte, []byte, error) { priv, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { return nil, nil, errors.New(fmt.Sprintf("failed to generate private key: %s", err)) } notBefore := time.Now() serialNumber, err := rand.Int(rand.Reader, new(big.Int).Lsh(big.NewInt(1), 128)) if err != nil { return nil, nil, errors.New(fmt.Sprintf("failed to generate serial number: %s", err)) } template := x509.Certificate{ SerialNumber: serialNumber, Subject: subject, NotBefore: notBefore, NotAfter: notBefore.Add(3650 * 24 * time.Hour), EmailAddresses: []string{email}, KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth}, UnknownExtKeyUsage: []asn1.ObjectIdentifier{ []int{1, 3, 6, 1, 4, 1, 311, 20, 2, 2}, // SmartCard Logon []int{1, 3, 6, 1, 4, 1, 311, 10, 3, 16}, // Verify signature for nonrepudiation? //'1.3.6.1.4.1.311.10.3.1' => 'certTrustListSigning' // '1.3.6.1.4.1.311.10.3.12' => 'szOID_KP_DOCUMENT_SIGNING', }, BasicConstraintsValid: true, } derBytes, err := x509.CreateCertificate(rand.Reader, &template, crtkit.CACert, &priv.PublicKey, crtkit.CAKey) if err != nil { return nil, nil, errors.New(fmt.Sprintf("Failed to create certificate: %s", err)) } certOut := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derBytes}) crypt_priv, err := x509.EncryptPEMBlock(rand.Reader, "RSA PRIVATE KEY", x509.MarshalPKCS1PrivateKey(priv), []byte(password), x509.PEMCipher3DES) if err != nil { return nil, nil, errors.New(fmt.Sprintf("Failed to encrypt: %s", err)) } keyOut := pem.EncodeToMemory(crypt_priv) return certOut, keyOut, nil }
// ExportEncryptedPrivate exports encrypted PEM-format private key func (k *Key) ExportEncryptedPrivate(password []byte) ([]byte, error) { var privBytes []byte switch priv := k.Private.(type) { case *rsa.PrivateKey: privBytes = x509.MarshalPKCS1PrivateKey(priv) default: return nil, errors.New("only RSA private key is supported") } privPEMBlock, err := x509.EncryptPEMBlock(rand.Reader, rsaPrivateKeyPEMBlockType, privBytes, password, x509.PEMCipher3DES) if err != nil { return nil, err } buf := new(bytes.Buffer) if err := pem.Encode(buf, privPEMBlock); err != nil { return nil, err } return buf.Bytes(), nil }
func EncryptPemBlock(block *pem.Block, password string, alg x509.PEMCipher) error { if 0 != len(password) { if x509.PEMCipher(0) == alg { alg = x509.PEMCipherAES256 } newBlock, err := x509.EncryptPEMBlock(rand.Reader, block.Type, block.Bytes, []byte(password), alg) if nil != err { return err } if nil == block.Headers { block.Headers = newBlock.Headers } else { for hdr, val := range newBlock.Headers { block.Headers[hdr] = val } } block.Bytes = newBlock.Bytes } return nil }
// EncryptPrivateKey returns an encrypted PEM key given a Privatekey // and a passphrase func EncryptPrivateKey(key data.PrivateKey, passphrase string) ([]byte, error) { blockType, err := blockType(key.Algorithm()) if err != nil { return nil, err } password := []byte(passphrase) cipherType := x509.PEMCipherAES256 encryptedPEMBlock, err := x509.EncryptPEMBlock(rand.Reader, blockType, key.Private(), password, cipherType) if err != nil { return nil, err } return pem.EncodeToMemory(encryptedPEMBlock), nil }
// EncryptPrivateKey returns an encrypted PEM key given a Privatekey // and a passphrase func EncryptPrivateKey(key *data.PrivateKey, passphrase string) ([]byte, error) { // TODO(diogo): Currently only supports RSA Private keys if key.Cipher() != "RSA" { return nil, errors.New("only RSA keys are currently supported") } password := []byte(passphrase) cipherType := x509.PEMCipherAES256 blockType := "RSA PRIVATE KEY" encryptedPEMBlock, err := x509.EncryptPEMBlock(rand.Reader, blockType, key.Private(), password, cipherType) if err != nil { return nil, err } return pem.EncodeToMemory(encryptedPEMBlock), nil }
// AEStoEncryptedPEM encapsulates an AES key in the encrypted PEM format func AEStoEncryptedPEM(raw []byte, pwd []byte) ([]byte, error) { if len(raw) == 0 { return nil, errors.New("Invalid aes key. It must be different from nil") } if len(pwd) == 0 { return AEStoPEM(raw), nil } block, err := x509.EncryptPEMBlock( rand.Reader, "AES PRIVATE KEY", raw, pwd, x509.PEMCipherAES256) if err != nil { return nil, err } return pem.EncodeToMemory(block), nil }
func generatePEM(randReader io.Reader, password []byte) (buf *bytes.Buffer, err error) { k, err := rsa.GenerateKey(randReader, 1024) if err != nil { return nil, err } derBytes := x509.MarshalPKCS1PrivateKey(k) var block *pem.Block if password != nil { block, err = x509.EncryptPEMBlock(randReader, "RSA PRIVATE KEY", derBytes, password, x509.PEMCipherAES128) } else { block = &pem.Block{ Type: "RSA PRIVATE KEY", Bytes: derBytes, } } buf = &bytes.Buffer{} err = pem.Encode(buf, block) return buf, err }
// EncryptPrivateKey returns an encrypted PEM encoded key given a Private key // and a passphrase func EncryptPrivateKey(key crypto.PrivateKey, passphrase string) ([]byte, error) { rsaKey, ok := key.(*rsa.PrivateKey) if !ok { return nil, errors.New("only RSA keys are currently supported") } keyBytes := x509.MarshalPKCS1PrivateKey(rsaKey) password := []byte(passphrase) cipherType := x509.PEMCipherAES256 blockType := "RSA PRIVATE KEY" encryptedPEMBlock, err := x509.EncryptPEMBlock(rand.Reader, blockType, keyBytes, password, cipherType) if err != nil { return nil, err } return pem.EncodeToMemory(encryptedPEMBlock), nil }
func (o *EncryptOptions) Encrypt() error { // Get data var data []byte var warnWhitespace = true switch { case len(o.CleartextFile) > 0: if d, err := ioutil.ReadFile(o.CleartextFile); err != nil { return err } else { data = d } case len(o.CleartextData) > 0: // Don't warn in cases where we're explicitly being given the data to use warnWhitespace = false data = o.CleartextData case o.CleartextReader != nil && util.IsTerminalReader(o.CleartextReader) && o.PromptWriter != nil: // Read a single line from stdin with prompting data = []byte(util.PromptForString(o.CleartextReader, o.PromptWriter, "Data to encrypt: ")) case o.CleartextReader != nil: // Read data from stdin without prompting (allows binary data and piping) if d, err := ioutil.ReadAll(o.CleartextReader); err != nil { return err } else { data = d } } if warnWhitespace && (o.PromptWriter != nil) && (len(data) > 0) { r1, _ := utf8.DecodeRune(data) r2, _ := utf8.DecodeLastRune(data) if unicode.IsSpace(r1) || unicode.IsSpace(r2) { fmt.Fprintln(o.PromptWriter, "Warning: Data includes leading or trailing whitespace, which will be included in the encrypted value") } } // Get key var key []byte switch { case len(o.KeyFile) > 0: if block, ok, err := pemutil.BlockFromFile(o.KeyFile, configapi.StringSourceKeyBlockType); err != nil { return err } else if !ok { return fmt.Errorf("%s does not contain a valid PEM block of type %q", o.KeyFile, configapi.StringSourceKeyBlockType) } else if len(block.Bytes) == 0 { return fmt.Errorf("%s does not contain a key", o.KeyFile) } else { key = block.Bytes } case len(o.GenKeyFile) > 0: key = make([]byte, 32) if _, err := rand.Read(key); err != nil { return err } } if len(key) == 0 { return errors.New("--genkey or --key is required") } // Encrypt dataBlock, err := x509.EncryptPEMBlock(rand.Reader, configapi.StringSourceEncryptedBlockType, data, key, x509.PEMCipherAES256) if err != nil { return err } // Write data if len(o.EncryptedFile) > 0 { if err := pemutil.BlockToFile(o.EncryptedFile, dataBlock, os.FileMode(0644)); err != nil { return err } } else if o.EncryptedWriter != nil { encryptedBytes, err := pemutil.BlockToBytes(dataBlock) if err != nil { return err } n, err := o.EncryptedWriter.Write(encryptedBytes) if err != nil { return err } if n != len(encryptedBytes) { return fmt.Errorf("could not completely write encrypted data") } } // Write key if len(o.GenKeyFile) > 0 { keyBlock := &pem.Block{Bytes: key, Type: configapi.StringSourceKeyBlockType} if err := pemutil.BlockToFile(o.GenKeyFile, keyBlock, os.FileMode(0600)); err != nil { return err } } return nil }
// Download an encrypted key in PEM format func (c Project) DownloadEncryptedKey(id, certId int, newKey, existingKey string) revel.Result { var user *models.User if c.RenderArgs["user"] == nil { c.Flash.Error("You must log in first") return c.Redirect(routes.App.Index()) } user = c.RenderArgs["user"].(*models.User) project := c.getProject(id) if project == nil { c.Flash.Error("Unable to load project") return c.Redirect(routes.App.Index()) } cert := c.getCert(certId) if cert == nil { c.Flash.Error("Unable to load certificate") return c.Redirect(routes.App.Index()) } cert_owners := c.getCertificateOwners(certId) project_owners := c.getProjectOwners(id) owns := false for _, owner := range cert_owners { if owner.Id == user.Id { owns = true } } for _, owner := range project_owners { if owner.Id == user.Id { owns = true } } if !user.IsAdmin || !owns { c.Flash.Error("You do not have permissions to download the key") return c.Redirect(routes.Project.Index(project.Id)) } block, _ := pem.Decode(cert.PrivateKey) if block == nil { c.Flash.Error("Unable to decode certificate") return c.Redirect(routes.Project.Index(project.Id)) } bytes := block.Bytes var err error // Need to decrypt if the key stored in the database is encrypted if len(existingKey) != 0 { bytes, err = x509.DecryptPEMBlock(block, []byte(existingKey)) if err != nil { c.Flash.Error("Error decrypting initial key") return c.Redirect(routes.Project.Index(project.Id)) } } var keyType string switch cert.KeyType { case models.RSA: keyType = "RSA PRIVATE KEY" case models.ECDSA: keyType = "EC PRIVATE KEY" } pemKeyBlock := &pem.Block{Type: keyType, Bytes: bytes} if len(newKey) > 0 { pemKeyBlock, err = x509.EncryptPEMBlock(rand.Reader, pemKeyBlock.Type, pemKeyBlock.Bytes, []byte(newKey), x509.PEMCipherAES256) if err != nil { c.Flash.Error("Error encrypting key") return c.Redirect(routes.Project.Index(project.Id)) } } else { c.Flash.Error("Need valid encryption key") return c.Redirect(routes.Project.Index(project.Id)) } privCert := pem.EncodeToMemory(pemKeyBlock) return Download(privCert) }
// NewOnDiskPBEKeys creates a new Keys structure with the specified key types // store under PBE on disk. If keys are generated and name is not nil, then a // self-signed x509 certificate will be generated and saved as well. func NewOnDiskPBEKeys(keyTypes KeyType, password []byte, path string, name *pkix.Name) (*Keys, error) { if keyTypes == 0 || (keyTypes & ^Signing & ^Crypting & ^Deriving != 0) { return nil, newError("bad key type") } if path == "" { return nil, newError("bad init call: no path for keys") } k := &Keys{ keyTypes: keyTypes, dir: path, } if len(password) == 0 { // This means there's no secret information: just load a public // verifying key. if k.keyTypes & ^Signing != 0 { return nil, newError("without a password, only a verifying key can be loaded") } err := k.loadCert() if err != nil { return nil, err } if k.Cert == nil { return nil, newError("no password and can't load cert: %s", k.X509Path()) } if k.VerifyingKey, err = FromX509(k.Cert); err != nil { return nil, err } } else { // There are two different types of keysets: in one there's // just a Signer, so we use an encrypted PEM format. In the // other, there are multiple keys, so we use a custom protobuf // format. if k.keyTypes & ^Signing != 0 { // Check to see if there are already keys. f, err := os.Open(k.PBEKeysetPath()) if err == nil { defer f.Close() ks, err := ioutil.ReadAll(f) if err != nil { return nil, err } data, err := PBEDecrypt(ks, password) if err != nil { return nil, err } defer ZeroBytes(data) var cks CryptoKeyset if err = proto.Unmarshal(data, &cks); err != nil { return nil, err } // TODO(tmroeder): defer zeroKeyset(&cks) ktemp, err := UnmarshalKeyset(&cks) if err != nil { return nil, err } // Note that this loads the certificate if it's // present, and it returns nil otherwise. err = k.loadCert() if err != nil { return nil, err } k.SigningKey = ktemp.SigningKey k.VerifyingKey = ktemp.VerifyingKey k.CryptingKey = ktemp.CryptingKey k.DerivingKey = ktemp.DerivingKey } else { // Create and store a new set of keys. k, err = NewTemporaryKeys(keyTypes) if err != nil { return nil, err } k.dir = path cks, err := MarshalKeyset(k) if err != nil { return nil, err } // TODO(tmroeder): defer zeroKeyset(cks) m, err := proto.Marshal(cks) if err != nil { return nil, err } defer ZeroBytes(m) enc, err := PBEEncrypt(m, password) if err != nil { return nil, err } if err = util.WritePath(k.PBEKeysetPath(), enc, 0777, 0600); err != nil { return nil, err } if k.SigningKey != nil && name != nil { err = k.newCert(name) if err != nil { return nil, err } } } } else { // There's just a signer, so do PEM encryption of the encoded key. f, err := os.Open(k.PBESignerPath()) if err == nil { defer f.Close() // Read the signer. ss, err := ioutil.ReadAll(f) if err != nil { return nil, err } pb, rest := pem.Decode(ss) if pb == nil || len(rest) > 0 { return nil, newError("decoding failure") } p, err := x509.DecryptPEMBlock(pb, password) if err != nil { return nil, err } defer ZeroBytes(p) err = k.loadCert() if err != nil { return nil, err } if k.SigningKey, err = UnmarshalSignerDER(p); err != nil { return nil, err } k.VerifyingKey = k.SigningKey.GetVerifier() } else { // Create a fresh key and store it to the PBESignerPath. if k.SigningKey, err = GenerateSigner(); err != nil { return nil, err } k.VerifyingKey = k.SigningKey.GetVerifier() p, err := MarshalSignerDER(k.SigningKey) if err != nil { return nil, err } defer ZeroBytes(p) pb, err := x509.EncryptPEMBlock(rand.Reader, "EC PRIVATE KEY", p, password, x509.PEMCipherAES128) if err != nil { return nil, err } pbes, err := util.CreatePath(k.PBESignerPath(), 0777, 0600) if err != nil { return nil, err } defer pbes.Close() if err = pem.Encode(pbes, pb); err != nil { return nil, err } if k.SigningKey != nil && name != nil { err = k.newCert(name) if err != nil { return nil, err } } } } } return k, nil }
func main() { flag.Parse() if *printVersion { fmt.Println("Quickcert v" + version) fmt.Println("https://github.com/andmarios/quickcert") os.Exit(0) } if len(*host) == 0 && !*isCA { fmt.Println("If you are not creating a CA pair, you need to set the -hosts parameter. Use -h for help.") os.Exit(1) } var cacert *x509.Certificate var cacertpem *pem.Block var cakey interface{} var err error // If not CA, read the CA key and cert if !*isCA { // Read CAcert log.Println("Reading CA certificate") data, err := readDecodePemFile(*CAcertFile) checkError("Could not read ca key file: ", err) cacert, err = x509.ParseCertificate(data.Bytes) checkError("Could not parse CA certificate: ", err) cacertpem = data // Read CAkey log.Println("Reading CA private key") data, err = readDecodePemFile(*CAkeyFile) checkError("Could not read ca key file: ", err) // If encrypted, decrypt it if x509.IsEncryptedPEMBlock(data) { password, err := readPassword("CA key is encrypted\nEnter password: "******"Error reading CA private key password: "******"Could not decrypt CA private key: ", err) } // Detect type and parse key if data.Type == "RSA PRIVATE KEY" { cakey, err = x509.ParsePKCS1PrivateKey(data.Bytes) checkError("Could not parse CA RSA private key: ", err) } else if data.Type == "EC PRIVATE KEY" { cakey, err = x509.ParseECPrivateKey(data.Bytes) checkError("Could not parse CA ECDSA key: ", err) } else { log.Fatalf("Could not find a compatible private key type (%s), only RSA and ECDSA are accepted", data.Type) } } // Create new key log.Println("Generating private key. This may take some time, depending on type and length.") var privkey interface{} switch *ecdsaCurve { case "": if *rsaBits < 2048 && !*isCA { log.Println("Consider upgrading your key to 2048 bits or better.") } else if *rsaBits < 4096 && *isCA { log.Println("Consider upgrading your CA key 4096 bits.") } privkey, err = rsa.GenerateKey(rand.Reader, *rsaBits) // I disabled P224 curve because Redhat patched their golang to // not support this curve due to patent law reasons. // I could leave it, but then quickcert won't compile on centos, rhel and fedora // case "P224": // privkey, err = ecdsa.GenerateKey(elliptic.P224(), rand.Reader) case "P256": privkey, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader) case "P384": privkey, err = ecdsa.GenerateKey(elliptic.P384(), rand.Reader) case "P521": privkey, err = ecdsa.GenerateKey(elliptic.P521(), rand.Reader) default: log.Fatalf("Unrecognized elliptic curve: %q", *ecdsaCurve) } checkError("Failed to generate private key: ", err) // Create certificate log.Println("Generating certificate.") var notBefore time.Time if len(*validFrom) == 0 { notBefore = time.Now() } else { notBefore, err = time.Parse("Jan 2 15:04:05 2006", *validFrom) checkError("Failed to parse creation date: ", err) } // time.Duration takes nanoseconds |--these are nsecs of a day--| duration := time.Duration(*validFor * 24 * 3600 * 1000 * 1000 * 1000) notAfter := notBefore.Add(duration) serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) checkError("Failed to generate serial number: ", err) template := x509.Certificate{ SerialNumber: serialNumber, Subject: pkix.Name{ Country: []string{}, Organization: []string{}, OrganizationalUnit: []string{}, CommonName: "", }, NotBefore: notBefore, NotAfter: notAfter, KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth}, BasicConstraintsValid: true, } if len(*cnAttr) > 0 { template.Subject.CommonName = *cnAttr } if len(*cAttr) > 0 { template.Subject.Country = append(template.Subject.Country, *cAttr) } if len(*oAttr) > 0 { template.Subject.Organization = append(template.Subject.Organization, *oAttr) } if len(*ouAttr) > 0 { template.Subject.OrganizationalUnit = append(template.Subject.OrganizationalUnit, *ouAttr) } hosts := strings.Split(*host, ",") for _, h := range hosts { if ip := net.ParseIP(h); ip != nil { template.IPAddresses = append(template.IPAddresses, ip) } else { template.DNSNames = append(template.DNSNames, h) } } if len(*email) > 0 { emails := strings.Split(*email, ",") for _, e := range emails { template.EmailAddresses = append(template.EmailAddresses, e) } } if *isCA { cakey = privkey cacert = &template template.IsCA = true template.KeyUsage |= x509.KeyUsageCertSign } // Sign certificate log.Println("Signing certificate") derBytes, err := x509.CreateCertificate(rand.Reader, &template, cacert, publicKey(privkey), cakey) checkError("Failed to create certificate: ", err) // Check if files to be written exist outCrt := *outFile + "crt.pem" outKey := *outFile + "key.pem" if _, err := os.Stat(outCrt); err == nil { checkError("Certificate file exists: ", userConfirmation("Certificate file ("+outCrt+") exists. Overwrite? [Yn]: ")) } if _, err := os.Stat(outKey); err == nil { checkError("Key file exists: ", userConfirmation("Key file ("+outKey+") exists. Overwrite? [Yn]: ")) } // Save certificate to file log.Println("Writing certificate file: ", outCrt) certOut, err := os.Create(outCrt) checkError("Failed to open "+outCrt+" for writing: ", err) pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}) if *chain { pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: cacertpem.Bytes}) } certOut.Close() // Save private key to file log.Println("Writing key file: ", outKey) keyOut, err := os.OpenFile(outKey, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) checkError("Failed to open key.pem for writing:", err) keyPemBlock := pemBlockForKey(privkey) if *encryptKey { ASK_KEY: pass1, err := readPassword("Enter password for private key: ") checkError("Error reading private key password, attempt 1: ", err) pass2, err := readPassword("Please re-enter password for private key: ") checkError("Error reading private key password, attempt 2: ", err) if string(pass1) == string(pass2) { keyPemBlock, err = x509.EncryptPEMBlock(rand.Reader, keyPemBlock.Type, keyPemBlock.Bytes, pass1, x509.PEMCipher3DES) } else { fmt.Println("Passwords mismatch. Try again.") goto ASK_KEY } } pem.Encode(keyOut, keyPemBlock) keyOut.Close() log.Println("Files written succesfully. Exiting.") }