易于在不安全网络上建立安全连接(两个端点完全受控)

huangapple go评论92阅读模式
英文:

Easy secure connection over unsafe network (both endpoints fully controlled)

问题

我需要在不受信任的网络上连接客户端和服务器。我考虑使用TLS (crypto/tls),但据我了解,我首先需要创建一个crypto/x509.Certificate。但是,我对需要传递给x509.CreateCertificate()函数的所有参数感到不知所措 - 它说它需要以下所有字段:

SerialNumber,Subject,NotBefore,NotAfter,KeyUsage,BasicConstraintsValid,IsCA,MaxPathLen,SubjectKeyId,DNSNames,PermittedDNSDomainsCritical,PermittedDNSDomains。

我对两个端点都有完全控制,所以我相信我不需要任何过期或无效化的支持/参数(我可以随时更改客户端和服务器上的密钥) - 所以我可能可以跳过NotBeforeNotAfter(?还是我必须设置它们?)。为了避免任何漏洞,我应该在所有其他字段中放入什么,以及为什么?另外,我可以在双向身份验证(客户端到服务器和服务器到客户端)中使用相同的私钥/公钥对,还是必须使用2对?

或者,有比TLS更简单的东西可以使用吗?但请注意,我需要双向身份验证。

编辑:

我根据接受答案的建议创建了一个简单的库,还使用了generate_cert.go中的密钥生成代码 - 请参阅:

github.com/akavel/tunnel

英文:

I need to connect client & server over untrusted network. I've considered using TLS (crypto/tls), but from what I understand, I first need to create a create a crypto/x509.Certificate. But I feel overwhelmed by all the parameters I need to pass to the x509.CreateCertificate() function - it says it needs all of the following fields:

> SerialNumber, Subject, NotBefore, NotAfter, KeyUsage, BasicConstraintsValid, IsCA, MaxPathLen, SubjectKeyId, DNSNames, PermittedDNSDomainsCritical, PermittedDNSDomains.

I have full control over both endpoints, so I believe I don't need any expiration or invalidation support/parameters (I can change keys both on client and server at any time I want) - so I can probably skip NotBefore and NotAfter (? or do I have to set them anyway?). What should I put in all the other fields, and why, to avoid any vulnerabilities? Also, can I use the same private/public key pair for both ways authentication (client to server, and server to client), or do I have to use 2 pairs?

Or, is there something simpler than TLS that I could use? Note however, that I need to two way authentication.

EDIT:

I created a simple library based on suggestions from the accepted answer, plus key generation code from generate_cert.go - see:

> github.com/akavel/tunnel

答案1

得分: 9

Owlstead部分正确。你最好使用OpenSSL创建自签名证书。然后,我会使用Go的TLS库进行加密。下面是一些可能会对你有帮助的代码。

创建x509密钥对

我通常按照这里的说明进行操作。以下是命令摘要(对客户端和服务器都要执行):

openssl genrsa -des3 -out server.key 1024
openssl req -new -key server.key -out server.csr
cp server.key server.key.org
openssl rsa -in server.key.org -out server.key
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt

使用Go的TLS库

首先,创建一个tls.Config。一个TLS配置可以在客户端和服务器上都使用,但某些选项只需要在其中一个上设置:

cert, err := tls.LoadX509KeyPair(cert, key)
config := &tls.Config{
    Certificates: []Certificates{cert},
    ClientAuth: tls.RequireAnyClientCert, // 必须在服务器上设置
    InsecureSkipVerify: true, // 必须在客户端上设置
}

在服务器上,你需要设置一个TLS监听器。这将在4443端口上进行设置:

listener, err := tls.Listen("tcp", ":4443", config)
for {
    conn, err := listener.Accept()
    acceptConn(conn) // 你的代码
}

在客户端上:

conn, err := tls.Dial("tcp", serverAddr, config)

这将创建一个加密连接,但不会验证对方是否是他们所说的那个人。最简单的方法是给每个服务器提供另一个服务器的公钥,并将其与刚刚连接的服务器进行比较。要在另一个服务器上找到公钥,你需要:

c := conn.(*tls.Conn) // 将listener的net.Conn转换为tls conn
err := c.Handshake() // 确保握手完成且没有错误
state := c.ConnectionState()
pubKey, err := x509.MarshalPKIXPublicKey(state.PeerCertificates[0])
bytes.Equal(pubKey, knownKey) // 与已知值进行比较
英文:

Owlstead is partly correct. Your best bet is creating self signed certificates using OpenSSL. However, I would then use the Go TLS library for encryption. Below is some code that may help you.

Creating an x509 key pair

I normally follow the instructions here. Summary of commands (do for both client and server):

openssl genrsa -des3 -out server.key 1024
openssl req -new -key server.key -out server.csr
cp server.key server.key.org
openssl rsa -in server.key.org -out server.key
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt

Using Go's TLS library

First, create a tls.Config. One TLS config will work on both client and server but some of the options only need to be set on one or the other:

cert, err := tls.LoadX509KeyPair(cert, key)
config := &tls.Config{
    Certificates: []Certificates{cert},
    ClientAuth: tls.RequireAnyClientCert, // Must be done on server
    InsecureSkipVerify: true, // Must be done on client
}

On the server, you need to setup a TLS listener. This sets it up on port 4443:

listener, err := tls.Listen("tcp", ":4443", config)
for {
    conn, err := listener.Accept()
    acceptConn(conn) // your code
}

On the client:

conn, err := tls.Dial("tcp", serverAddr, config)

This will create an encrypted connection, but it will not verify the other side is who they say they are. The easiest way to do that is to give each server the public key of the other server and compare it to the server that has just connected. To find the public key on the other server, you need to:

c := conn.(*tls.Conn) // convert net.Conn from listener to tls conn
err := c.Handshake() // ensure handshake is completed without error
state := c.ConnectionState()
pubKey, err := x509.MarshalPKIXPublicKey(state.PeerCertificates[0])
bytes.Equal(pubKey, knownKey) // compare to known value

答案2

得分: 0

正如owlstead所说,TLS仍然是你最好的选择。你可以通过遵循一些在线指南来创建自己的证书。

以下文章可以帮助你创建自己的SSL根证书(你实际上成为了自己的根CA,就像Verisign等)。有了这个,你可以创建和签署自己的应用程序证书并分发它们。如果像你所说,你对两个端点都有完全控制权,那么这可能值得一试。

http://www.eclectica.ca/howto/ssl-cert-howto.php/

英文:

As owlstead stated, TLS is still your best bet. Creating your own certificates can be done by following some online guide.

The following article lets you create your own SSL root certificate (You effectively become your own Root CA, like Verisign and such). With this, you can create and sign your own application certificates and distribute them. If, as you say, you have full control over both end points, this is probably worth checking in to.

http://www.eclectica.ca/howto/ssl-cert-howto.php/

huangapple
  • 本文由 发表于 2012年9月3日 04:37:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/12239555.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定