I'm setting up a https server in Go using the following function.
err := http.ListenAndServeTLS(":8080", key, cert, nil)
if err != nil {
log.Fatal("error...")
}
Where key and cert are respectively self-signed key and certificate files.
My problem is that for security I need to validate they self-signed key to have a 2048 bits size (or more).
How can I securely and cleanly check for this in Go?
package main
import (
"crypto/ecdsa"
"crypto/rsa"
"crypto/tls"
"log"
"net/http"
)
func main() {
certFile := "/tmp/cert.pem"
keyFile := "/tmp/key.pem"
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
if err != nil {
log.Fatal(err)
}
var bitLen int
switch privKey := cert.PrivateKey.(type) {
case *rsa.PrivateKey:
bitLen = privKey.N.BitLen()
case *ecdsa.PrivateKey:
bitLen = privKey.Curve.Params().BitSize
default:
log.Fatal("unsupported private key")
}
if bitLen < 2048 {
log.Fatalf("private key length is too small (size: %d)\n", bitLen)
}
tlsConfig := tls.Config{
Certificates: []tls.Certificate{cert},
}
server := http.Server{
Addr: ":8080",
TLSConfig: &tlsConfig,
}
if err := server.ListenAndServeTLS("", ""); err != nil {
log.Fatal(err)
}
}
Related
I am trying to find a way to keychain https client certificate based authentication from macOS system. When I export the certificate and the key I can already successfully connect to my server, but that is not my goal. From the keychain it looks more difficult. I can't get the private key into the TLS Certificate Config. Maybe someone has an idea or a better way. Thanks a lot
package main
import (
"crypto/tls"
"io/ioutil"
"log"
"net/http"
"os"
"github.com/github/certstore"
"crypto/x509"
)
func HttpClient() (client *http.Client) {
// Open Keychain Certificate System Store
store, err := certstore.Open()
if err != nil {
log.Println(err)
}
defer store.Close()
// Get all in Identities
idents, err := store.Identities()
if err != nil {
log.Println(err)
}
// Iterate through the identities, looking for the one we want.
var me certstore.Identity
for _, ident := range idents {
defer ident.Close()
crt, errr := ident.Certificate()
if errr != nil {
log.Println(errr)
}
if crt.Subject.CommonName == "SCEP Identity UUID12345" {
me = ident
log.Println(crt.Subject.CommonName)
log.Println("Org: ",crt.Subject.Organization)
log.Println("Signer:", ident.Signer)
// Everything works fine when i load the cert and key from disk.
// x509cert, err := tls.LoadX509KeyPair("client.pem", "client.key")
chain, _ := ident.CertificateChain()
signer, er := me.Signer()
if er != nil {
log.Println("PrivateKey Error:",er)
}
certsnew := tls.Certificate{
Leaf: chain[0],
Certificate: serializeChain(chain),
PrivateKey: signer,
}
// Test to create KeyPair but does not work
// Error: cannot use signer (type crypto.Signer) as type []byte in argument to tls.X509KeyPair
tlsKeyPair, err := tls.X509KeyPair(chain[0].Raw, signer)
certs := []tls.Certificate{certsnew}
// if len(certs) == 0 {
// client = &http.Client{}
// return
// }
tr := &http.Transport{
TLSClientConfig: &tls.Config{Certificates: certs,
InsecureSkipVerify: true,
Renegotiation: tls.RenegotiateOnceAsClient},
}
client = &http.Client{Transport: tr}
}
}
return
}
I try to add tls config to "github.com/eclipse/paho.mqtt.golang" client package. However in the config pems load from a file. I want to use pem as string format. For example an object has "caPem" key and its value CA pem as string.
func NewTLSConfig(cACertificate, clientCertificate, clientKey string) *tls.Config {
certpool := x509.NewCertPool()
pemCerts, err := ioutil.ReadFile("/ca.pem")
if err == nil {
certpool.AppendCertsFromPEM(pemCerts)
}
cert, err := tls.LoadX509KeyPair("/client.pem", "/client.key")
if err != nil {
panic(err)
}
cert.Leaf, err = x509.ParseCertificate(cert.Certificate[0])
if err != nil {
panic(err)
}
fmt.Println(cert.Leaf)
return &tls.Config{
RootCAs: certpool,
ClientAuth: tls.RequestClientCert,
ClientCAs: nil,
InsecureSkipVerify: false,
Certificates: []tls.Certificate{cert},
}
}
As you see above code , pemCerts get public key from a file. Functions parameters "caCertificate..." are string. I just want to use them like "pemCerts := caCertificate". How can I implement this
Made an example, of how to this this. It does assume that you do not have more than 1 PEM block in the string. If you do you should adapt it to call strPEMToPubCert multiple times.
(playground link)
package main
import (
"crypto/x509"
"encoding/pem"
"errors"
"fmt"
)
func main() {
var pubPEMData = `-----BEGIN CERTIFICATE-----
MIIG9TCCBd2gAwIBAgISBLS106X/pLzr6OgL1QIQaFjHMA0GCSqGSIb3DQEBCwUA
MDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQD
EwJSMzAeFw0yMTEyMDUxNDE1NTJaFw0yMjAzMDUxNDE1NTFaMB4xHDAaBgNVBAMM
Eyouc3RhY2tleGNoYW5nZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
AoIBAQCad2WyTsmxXwoyz/iQST49XuSAciGr8GcyUtrestK82l4uHvU0/eCsxkUa
nT6xpm60l9OaAXCjJHEl9+0qKOUQ8+FJzr4W9PuiALE1E6j5mpYk3FRERZwX+AFZ
dN2G1rSb+uZvDSiR9eUikj0ueR5TTA+ZUsNLaByE+/EzcUqja9Qxyq7zkizSolxy
/RVTRPB2BaDkGY4I46avu8PJPm6R3skp0L96MnWSDVtJhIGc5lisoUEozrlTbTuT
SfBvPAAIqFT6702LJqFIF5rW04++GrEBh6S1I+17IZxneTMcorx0sYmXVzRGvz6e
0nOfXo6a80hAFgs+vci3UWEze7vrAgMBAAGjggQXMIIEEzAOBgNVHQ8BAf8EBAMC
BaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAw
HQYDVR0OBBYEFMbQN0TT6bdr8CA4WpQ9UwT/XKTZMB8GA1UdIwQYMBaAFBQusxe3
WFbLrlAJQOYfr52LFMLGMFUGCCsGAQUFBwEBBEkwRzAhBggrBgEFBQcwAYYVaHR0
cDovL3IzLm8ubGVuY3Iub3JnMCIGCCsGAQUFBzAChhZodHRwOi8vcjMuaS5sZW5j
ci5vcmcvMIIB5AYDVR0RBIIB2zCCAdeCDyouYXNrdWJ1bnR1LmNvbYISKi5ibG9n
b3ZlcmZsb3cuY29tghIqLm1hdGhvdmVyZmxvdy5uZXSCGCoubWV0YS5zdGFja2V4
Y2hhbmdlLmNvbYIYKi5tZXRhLnN0YWNrb3ZlcmZsb3cuY29tghEqLnNlcnZlcmZh
dWx0LmNvbYINKi5zc3RhdGljLm5ldIITKi5zdGFja2V4Y2hhbmdlLmNvbYITKi5z
dGFja292ZXJmbG93LmNvbYIVKi5zdGFja292ZXJmbG93LmVtYWlsgg8qLnN1cGVy
dXNlci5jb22CDWFza3VidW50dS5jb22CEGJsb2dvdmVyZmxvdy5jb22CEG1hdGhv
dmVyZmxvdy5uZXSCFG9wZW5pZC5zdGFja2F1dGguY29tgg9zZXJ2ZXJmYXVsdC5j
b22CC3NzdGF0aWMubmV0gg1zdGFja2FwcHMuY29tgg1zdGFja2F1dGguY29tghFz
dGFja2V4Y2hhbmdlLmNvbYISc3RhY2tvdmVyZmxvdy5ibG9nghFzdGFja292ZXJm
bG93LmNvbYITc3RhY2tvdmVyZmxvdy5lbWFpbIIRc3RhY2tzbmlwcGV0cy5uZXSC
DXN1cGVydXNlci5jb20wTAYDVR0gBEUwQzAIBgZngQwBAgEwNwYLKwYBBAGC3xMB
AQEwKDAmBggrBgEFBQcCARYaaHR0cDovL2Nwcy5sZXRzZW5jcnlwdC5vcmcwggEF
BgorBgEEAdZ5AgQCBIH2BIHzAPEAdwDfpV6raIJPH2yt7rhfTj5a6s2iEqRqXo47
EsAgRFwqcwAAAX2LKmpMAAAEAwBIMEYCIQC1jB7OwpQiHacbVnEZgWegpCOksm6Z
TYkTjXCmIo9m1AIhAPjs+1PPNr/avFzSydhUROI+Rvqx0iZqXzNc24PIOXjBAHYA
KXm+8J45OSHwVnOfY6V35b5XfZxgCvj5TV0mXCVdx4QAAAF9iypqRAAABAMARzBF
AiEA0oJ418l3aDXj4EVAtzf5o2nUdYiZiH7pLvA1hd7ZSKUCICFeACPl73NNLSzR
7yoKEV6nO7Zlk4rUd/fUyROY35OMMA0GCSqGSIb3DQEBCwUAA4IBAQB+hvmbEaHF
jEkSZiTllNe+XWtfz6TiWIugoqdDL67app49ZTTZ94oLRGxybm62nBIEX/2gCRgd
fqnDecg4BWIyl2jti73eKkmt9+pcCDqZ1JcbW8rDLmZJnzdcC0o739BGRq/ufP5R
Fb8qXAap2VH/29MQImxB166PsAb9rKdS1kNSfg4Zsu7nisg7q47dyzZMT9cTbajf
D/T6hl30nHOyJFvny5vYwDLtiNg5BJ2xZzZFh4B73mY53jjN2EXn4S5LI9J+0NmY
dic7TY+lsttvfrJ+cySMO7E1T1SkgEgHtfsadlRRWNFl80R91sS98FHbhBg/MSMk
yAm4xgff5rYD
-----END CERTIFICATE-----`
crt, _, err := strPEMToPubCert(pubPEMData)
if err != nil {
panic(err)
}
fmt.Println(crt.DNSNames)
}
func strPEMToPubCert(pemStr string) (*x509.Certificate, []byte, error) {
block, rest := pem.Decode([]byte(pemStr))
if block == nil || block.Type != "CERTIFICATE" {
return nil, rest, errors.New("failed to decode PEM block containing certificate")
}
cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
return nil, rest, err
}
return cert, rest, nil
}
I am tring to generate dkim key using golang, my current code is :
package appdkim
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/asn1"
"encoding/pem"
"fmt"
"os"
)
func Keymaker(path string) {
reader := rand.Reader
bitSize := 2048
key, err := rsa.GenerateKey(reader, bitSize)
checkError(err)
publicKey := key.PublicKey
savePEMKey(path+".priv", key)
savePublicPEMKey2(path+".pub", publicKey)
return
}
func savePEMKey(fileName string, key *rsa.PrivateKey) {
outFile, err := os.Create(fileName)
checkError(err)
defer outFile.Close()
var privateKey = &pem.Block{
Type: "PRIVATE KEY",
Bytes: x509.MarshalPKCS1PrivateKey(key),
}
err = pem.Encode(outFile, privateKey)
checkError(err)
}
func savePublicPEMKey2(fileName string, pubkey rsa.PublicKey) {
//var PublicKeyRow bytes.Buffer
var pemkey = &pem.Block{
Type: "PUBLIC KEY",
Bytes: x509.MarshalPKCS1PublicKey(&pubkey),
}
pemfile, err := os.Create(fileName)
checkError(err)
defer pemfile.Close()
err = pem.Encode(pemfile, pemkey)
checkError(err)
//err = pem.Encode(&PublicKeyRow, pemkey)
//checkError(err)
//return PublicKeyRow.String()
}
func checkError(err error) {
if err != nil {
fmt.Println("Fatal error ", err.Error())
os.Exit(1)
}
}
the code is working, generate the dkim private/public keys, problem is this keys return bad keys by sender, if i generate keys using this site : https://easydmarc.com/tools/dkim-record-generator/ the keys results valid.
this is my dkim settings in dns :
v=DKIM1;t=s;p=MIGJAoGBD1DSPRFFTujiCAiadP9ZeA6eAyf0GktfCQO2WKbrAx2Cu15y2A+agQMWNTmZbbhcznGZiz3kA9y7c0wOqN2iaJchBAxt4qdg1vUhy+6CkSZcY5bdm8uOxsXW3gjOTyZrOur/c118wMTOmSJKHOjn9xLG3ta8tXJtqab8idtx4TlBAgMBAAE=
I try to understend what if diferent with my golang key like key generated by easydmarc.com. What i need to change to my golang code for be valid for dkim validation ?
I am tring to generate dkim key using golang, my current code is :
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/asn1"
"encoding/gob"
"encoding/pem"
"fmt"
"os"
)
func Keymaker(path string) {
reader := rand.Reader
bitSize := 2048
key, err := rsa.GenerateKey(reader, bitSize)
checkError(err)
publicKey := key.PublicKey
//saveGobKey("private.key", key)
savePEMKey(path+".priv", key)
//saveGobKey("public.key", publicKey)
savePublicPEMKey(path+".pub", publicKey)
}
func savePEMKey(fileName string, key *rsa.PrivateKey) {
outFile, err := os.Create(fileName)
checkError(err)
defer outFile.Close()
var privateKey = &pem.Block{
Type: "PRIVATE KEY",
Bytes: x509.MarshalPKCS1PrivateKey(key),
}
err = pem.Encode(outFile, privateKey)
checkError(err)
}
func savePublicPEMKey(fileName string, pubkey rsa.PublicKey) {
asn1Bytes, err := asn1.Marshal(pubkey)
checkError(err)
var pemkey = &pem.Block{
Type: "PUBLIC KEY",
Bytes: asn1Bytes,
}
pemfile, err := os.Create(fileName)
checkError(err)
defer pemfile.Close()
err = pem.Encode(pemfile, pemkey)
checkError(err)
}
func checkError(err error) {
if err != nil {
fmt.Println("Fatal error ", err.Error())
os.Exit(1)
}
}
the code is working, generate the dkim private/public keys, problem is this keys return bad keys by sender, if i generate keys using this site : https://easydmarc.com/tools/dkim-record-generator/ the keys results valid.
this is my dkim settings in dns :
v=DKIM1;t=s;p=MIGJAoGBD1DSPRFFTujiCAiadP9ZeA6eAyf0GktfCQO2WKbrAx2Cu15y2A+agQMWNTmZbbhcznGZiz3kA9y7c0wOqN2iaJchBAxt4qdg1vUhy+6CkSZcY5bdm8uOxsXW3gjOTyZrOur/c118wMTOmSJKHOjn9xLG3ta8tXJtqab8idtx4TlBAgMBAAE=
i try to understend way keys generated by easydmarc.com working, and golang keys not working. Any ideea ?
I am trying with the following code by passing cert.pem, key.pem and ..chain.pem but getting status:500 as the service is not able to read these certificates for https RESTful webservice. I went through all the examples in net and tried but still getting same exception.
package main
import (
"crypto/tls"
"crypto/x509"
"fmt"
"io/ioutil"
"log"
"net/http"
"strings"
"io"
)
func main() {
UserName := "user"
appName := "AP"
PasswordKey := "key"
ServerName := "server"
Sid := "sid"
// Load client cert
cert, err := tls.LoadX509KeyPair("/cert.pem", "/key.pem")
if err != nil {
log.Fatal(err)
}
// Load CA cert
caCert, err := ioutil.ReadFile("/xyz.chain.pem")
if err != nil {
log.Fatal(err)
}
caCertPool := x509.NewCertPool()
ok := caCertPool.AppendCertsFromPEM(caCert)
if !ok {
panic("failed to parse root certificate")
}
fmt.Println("CERT: ",cert)
// Setup HTTPS client
tlsConfig := &tls.Config{
Certificates: []tls.Certificate{cert},
ServerName: "serverName",
RootCAs: caCertPool,
}
tlsConfig.BuildNameToCertificate()
transport := &http.Transport{TLSClientConfig: tlsConfig}
client := &http.Client{Transport: transport}
fmt.Println("CLIENT: ",client)
r := strings.NewReader("{\"userName\" : \"" +UserName+"\",\"appName\" : \""+appName+"\",\"passwordKey\" : \""+PasswordKey+"\",\"serverName\" : \""+ServerName+"\",\"sid\" : \""+Sid+"\"}")
lr := io.Reader(r)
resp, err := client.Post("https://xzytr/password/txt","application/json",lr)
if err != nil {
fmt.Println(err)
}
contents, err := ioutil.ReadAll(resp.Body)
fmt.Printf("%s\n", string(contents))
}