loading certificate and https.Get

2,231 views
Skip to first unread message

Sebastien Binet

unread,
Sep 27, 2012, 7:08:09 AM9/27/12
to golang-nuts
hi there,

I am trying to issue a GET request on some server, using a x509
certificate for authentication (beware: I am a total ignorant in this
matter so I may use incorrect terms and vocabulary)

I got a certificate (from CERN, if that matters) and I am pretty
confident it all works (I used curl to test everything)

here is what I did to get PEM files:


$ openssl pkcs12 -in mycert.pfx -clcerts -nokeys -out usercert.pem
$ openssl pkcs12 -in mycert.pfx -nocerts -out userkey.pem
$ chmod 400 userkey.pem
$ chmod 444 usercert.pem

$ curl -G "https://somewhere.at.cern.ch:someport/somepage" -k --cert
usercert.pem --key userkey.pem
Enter PEM pass phrase: <secret>
<lines of output as I expected>

now, trying to do the same using net/http:

```go
package main

import (
"fmt"
"net/http"
"net/url"
"crypto/tls"
"os"
)

func checkError(err error, hdr string) {
if err != nil {
fmt.Printf("[%s] Fatal error: %v\n", hdr, err.Error())
os.Exit(1)
}
}

func main() {
rurl, err := url.Parse("https://somewhere.at.cern.ch:someport/somepage")
checkError(err, "url.Parse")

cert, err := tls.LoadX509KeyPair("usercert.pem", "userkey.pem")
checkError(err, "loadcert")

tr := &http.Transport{
TLSClientConfig: &tls.Config{
Certificates: []tls.Certificate {cert},
InsecureSkipVerify: true,
ClientAuth: tls.RequireAnyClientCert,
},
}
client := &http.Client{Transport: tr}

req, err := http.NewRequest("GET", rurl.String(), nil)
checkError(err, "http.NewRequest")
fmt.Printf("request: %v\n", *req)

resp, err := client.Do(req)
checkError(err, "client.Do")
if resp.Status != "200 OK" {
fmt.Println(resp.Status)
os.Exit(2)
}

var buf [512]byte
reader := resp.Body
fmt.Println("got body")
for {
n, err := reader.Read(buf[0:])
if err != nil {
os.Exit(0)
}
fmt.Print(string(buf[0:n]))
}

os.Exit(0)
}

```

$ go run ./nuts.go

[loadcert] Fatal error: crypto/tls: failed to parse key: ASN.1
structure error: tags don't match (2 vs {class:0 tag:16 length:64
isCompound:true}) {optional:false explicit:false application:false
defaultValue:<nil> tag:<nil> stringType:0 set:false omitEmpty:false}
int @2
exit status 1

so, I am obviously not doing something right...
any idea what I should do to fix this ?

thx,
-s

agl

unread,
Sep 27, 2012, 9:31:04 AM9/27/12
to golan...@googlegroups.com
On Thursday, September 27, 2012 7:08:19 AM UTC-4, Sebastien Binet wrote:
[loadcert] Fatal error: crypto/tls: failed to parse key: ASN.1
structure error: tags don't match (2 vs {class:0 tag:16 length:64
isCompound:true}) {optional:false explicit:false application:false
defaultValue:<nil> tag:<nil> stringType:0 set:false omitEmpty:false}
int @2
exit status 1

Could you include the first line of the key file (the "BEGIN" line).


Cheers

AGL 
 

Sebastien Binet

unread,
Sep 27, 2012, 9:39:58 AM9/27/12
to agl, golan...@googlegroups.com
that's:
-----BEGIN ENCRYPTED PRIVATE KEY-----

well, actually, there are a few bits before:
Bag Attributes
friendlyName: me
localKeyID: some-hex
Key Attributes: <No Attributes>

if that matters...

-s

>
>
> Cheers
>
> AGL
>>
>>
>
> --
>
>

Adam Langley

unread,
Sep 27, 2012, 9:56:07 AM9/27/12
to Sebastien Binet, golan...@googlegroups.com
On Thu, Sep 27, 2012 at 9:39 AM, Sebastien Binet <seb....@gmail.com> wrote:
> -----BEGIN ENCRYPTED PRIVATE KEY-----

That's the issue: we don't support encrypted private keys via that
interface I'm afraid. (Although general support is in
https://codereview.appspot.com/6555052/, which I hope to land this
afternoon.)

If you can load the cert and key yourself, you can patch that CL in
and decrypt it.

Alternatively, if it's acceptable to you, you can decrypt the private
key and load the unencrypted private key from disk:

openssl rsa -in encrypted.key > decrypted.key


Cheers

AGL

Sebastien Binet

unread,
Sep 27, 2012, 1:22:23 PM9/27/12
to Adam Langley, golan...@googlegroups.com
Adam,
ok, thanks, that helped a lot.
turns out my encrypted.key does not have the headers the CL is
mentioning (ie: no such "DEK-Info") but I can live with exec.Cmd'ing
openssl to decrypt the key for the moment.

thanks again,
-s

Adam Langley

unread,
Sep 27, 2012, 2:09:13 PM9/27/12
to Sebastien Binet, golan...@googlegroups.com
On Thu, Sep 27, 2012 at 1:22 PM, Sebastien Binet <seb....@gmail.com> wrote:
> turns out my encrypted.key does not have the headers the CL is
> mentioning (ie: no such "DEK-Info") but I can live with exec.Cmd'ing
> openssl to decrypt the key for the moment.

Thanks for the head's up. I was vaguely aware that there was a form of
encrypted key that worked differently but, if people are using it in
the wild, I'll try to support it in the future.


Cheers

AGL

jfcg...@gmail.com

unread,
Nov 5, 2013, 1:42:28 AM11/5/13
to golan...@googlegroups.com
Greetings,

I am creating a test EC certificate with OpenSSL 1.0.1e via these commands:
openssl ecparam -out ecpar.pem -name secp224r1
openssl req -x509 -days 444 -newkey ec:ecpar.pem -keyout priv.pem -out pub.pem

then I am using (1.2rc3) pem.Decode and x509.DecryptPEMBlock to get priv key but i am getting a "DEK info not found error". Am I missing something ?

Jeff R. Allen

unread,
Nov 5, 2013, 11:16:25 AM11/5/13
to golan...@googlegroups.com, jfcg...@gmail.com
When I use these commands:

openssl ecparam -out ecpar.pem -name secp224r1
openssl req -x509 -days 444 -newkey ec:ecpar.pem -keyout priv.pem -out pub.pem

I get a priv.pem like this:

-----BEGIN EC PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,23F8D3C4F3E54362

M0FFdRyIQAnOJsMb0inutQS+Z1b1WdShEM8G2rsEQSRxSp+DSa8yiYJJQrEQ50gG
ZjAzcVxRF5OpXyWgE0RmoycYLf2svrBo3GBnj6aKcsHkCuqwqEwM7dWgxLAmcB47
Hah0pi3f3PQj/HiI1P6FuA==
-----END EC PRIVATE KEY-----

(What does yours look like? Does it have the same two headers in it? Please remember this is supposed to be a private key, if you want to send yours for us to look at, send a throw-away one.) 

With that priv.key x509.DecryptPEMBlock will correctly read the key out of that file. (I had to take the implementation of tls.LoadX509KeyPair and hack it up to add in a call to x509.DecryptPEMBlock; perhaps you can show how you are doing that?)

When I go on to try to use that key and the sell-signed cert in "pub.pem", I get the following panic:

2013/11/05 17:06:32 http: panic serving [::1]:51547: interface conversion: interface is *ecdsa.PrivateKey, not *rsa.PrivateKey
goroutine 8 [running]:
net/http.func·007()
/Users/jeffall/go/src/pkg/net/http/server.go:1022 +0xac
crypto/tls.(*ecdheRSAKeyAgreement).generateServerKeyExchange(0xc2000a0480, 0xc2000a1750, 0xc20009bbe0, 0xc2000e63c0, 0xc200113f00, ...)
/Users/jeffall/go/src/pkg/crypto/tls/key_agreement.go:154 +0x4d7
 
So that's apparently what's waiting for you once you get your key loaded correctly... :)

  -jeff

PS: go version go1.1.2 darwin/amd64

Jeff R. Allen

unread,
Nov 5, 2013, 11:39:05 AM11/5/13
to golan...@googlegroups.com
With go version go1.2rc3 darwin/amd64 and openssl-1.0.1e, ECDSA worked for me (using the commands you posted to generate the key and the self-signed cert).

I was not able to connect from Chrome to the Go-based server, however (ERR_SSL_VERSION_OR_CIPHER_MISMATCH).

Hope this helps.

  -jeff

PS: The hacked up server code I'm using is: http://play.golang.org/p/8OYTuZtZIQ

Michael Gehring

unread,
Nov 5, 2013, 1:59:40 PM11/5/13
to jfcg...@gmail.com, golan...@googlegroups.com
On Mon, Nov 04, 2013 at 10:42:28PM -0800, jfcg...@gmail.com wrote:
> Greetings,
>
> I am creating a test EC certificate with OpenSSL 1.0.1e via these commands:
>
> openssl ecparam -out ecpar.pem -name secp224r1
>
> openssl req -x509 -days 444 -newkey ec:ecpar.pem -keyout priv.pem -out pub.pem
>
>
> then I am using (1.2rc3) pem.Decode and x509.DecryptPEMBlock to get priv key but i am getting a "DEK info not found error". Am I missing something ?

The generated key (at least here linux/openssl 1.0.1e) is in PKCS8
format and I couldn't find an option to force it to use the traditional
format (which uses the DEK-Info header).

Since x509.DecryptPEMBlock only understands the traditional format and
x509.ParsePKCS8PrivateKey only supports unencrypted keys, there currently
seems no way to use these keys directly. One option is to remove the
encryption on the private key (openssl pkcs8 -in priv.pem) or convert it
to the traditional format (unfortunately there seems no support for this in
the openssl commandline tools?).

Michael Gehring

unread,
Nov 5, 2013, 2:39:32 PM11/5/13
to jfcg...@gmail.com, golan...@googlegroups.com
The pkcs8 key can be converted to the traditional format with:
openssl ec -in <key> -<cipher>
e.g.
openssl ec -in priv.pem -aes128


jfcg...@gmail.com

unread,
Nov 5, 2013, 4:56:06 PM11/5/13
to golan...@googlegroups.com
On Tuesday, November 5, 2013 6:39:05 PM UTC+2, Jeff R. Allen wrote:
PS: The hacked up server code I'm using is: http://play.golang.org/p/8OYTuZtZIQ

I think this example is a good justification for improving crypto/x509. Using ECC, and keeping private keys encrypted is a very natural use case, we shouldnt be needing this much of a tumbling. Thanks for the example btw..

Also, I am trying to get an encrypted EC private key in one command and I get the following error. Is this an OpenSSL bug maybe ? :

$ openssl.exe genpkey -out priv.pem -aes128 -algorithm EC -pkeyopt ec_paramgen_curve:secp224r1
parameter setting error
3512:error:06089094:digital envelope routines:EVP_PKEY_CTX_ctrl:invalid operation:.\crypto\evp\pmeth_lib.c:404

Jeff R. Allen

unread,
Nov 6, 2013, 8:02:54 AM11/6/13
to golan...@googlegroups.com, jfcg...@gmail.com

I think this example is a good justification for improving crypto/x509.

Van Hu

unread,
Dec 31, 2014, 9:48:57 AM12/31/14
to golan...@googlegroups.com
This link seems to solve my problem nicely.


sock, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK"))
if err != nil {
    log
.Fatal(err)
}

agent
:= agent.NewClient(sock)

signers
, err := agent.Signers()
if err != nil {
    log
.Fatal(err)
}

auths
:= []ssh.AuthMethod{ssh.PublicKeys(signers...)}

cfg
:= &ssh.ClientConfig{
   
User: "username",
   
Auth: auths,
}
cfg
.SetDefaults()

client
, err := ssh.Dial("tcp", "aws-hostname:22", cfg)
if err != nil {
    log
.Fatal(err)
}

session
, err = client.NewSession()
if err != nil {
    log
.Fatal(err)
}

log
.Println("we have a session!")

...


Reply all
Reply to author
Forward
0 new messages