英文:
Reading and writing over a tls.Server connection
问题
我正在使用Go语言编写一个SMTP服务器。实现STARTTLS命令需要使用crypto/tls
包。在这里,我应该能够将net.Conn
对象“转换”为tls.Conn
对象,然后我就可以无缝地使用TLS提供的加密进行读写操作。
然而,即使我能够完成上述的第一部分,当我尝试读取或写入TLS保护的连接时,调用的Read()
和Write()
函数并不是tls.Conn
对象的函数,而是底层的net.Conn
对象的函数。
我目前的做法如下:
type Handler struct {
Conn net.Conn
}
//...
client := Handler{Conn: /*socket*/}
client.Conn.Write([]byte("Hello!")) //普通写入
//已接收到STARTTLS命令,切换到tls.Conn并进行握手
client.Conn = tls.Server(client.Conn, &TlsConfig) //client.Conn现在应该是tls.Conn类型
//无论是进行类型转换还是不进行类型转换,结果都是一样的
client.Conn.Handshake() //不是必需的,因为默认情况下会在第一次Read()或Write()时调用
//...
client.Conn.Write([]byte("Hello again!")) //写入明文、未加密的文本
//...
rdr := bufio.NewReader(client.Conn) //这可能是问题所在吗?我认为不是,因为它只是包装了常规函数
line, err := rdr.ReadString/*or Line*/('\n')
//...
//line = 类似于"�'�9����"和其他客户端加密文本
我看到很多人,包括标准的`net/smtp`包,使用`text/proto`包来解析客户端命令。然而,我想使用自己的解析器(并且也想解决这个问题)。正如前面的注释所说,我认为问题不在这里,因为它只是包装了函数,不是吗?
可能是`client.Conn = tls.Server(client.Conn, &TlsConfig)`这个对象切换的问题吗?
我正在使用自签名的SSL密钥和证书,使用OpenSSL生成。为了测试,我使用了上面链接的StackOverflow问题中提到的两种方法:`openssl s_client -starttls smtp -crlf [-tls1] -connect localhost:25`和简单的`net/smtp.SendMail()`调用。我正在使用Go 1.2.1 (linux/amd64)进行编译。
我还尝试使用Wireshark进行抓包,确实发现了我上面说的情况。此外,调用Handshake()似乎并没有实际进行握手。
我做错了什么?
<details>
<summary>英文:</summary>
I'm writing an SMTP server in Go. Implementing the STARTTLS command requires usage of the `crypto/tls` package.
[Here](https://stackoverflow.com/questions/13110713/upgrade-a-connection-to-tls-in-go) seems like I should be able to "convert" the net.Conn object to a tls.Conn one, and then I'd be able to seamlessly read and write using the encryption TLS provides.
However, even if I'm able to do the first part of the above, when I try to read or write to the TLS-protected connection, the Read() and Write() functions called are not the ones of the tls.Conn object, but of the underlying net.Conn one.
What I'm currently doing looks like this:
<!-- language: go -->
type Handler struct {
Conn net.Conn
}
//...
client := Handler{Conn: /*socket*/}
client.Conn.Write([]byte("Hello!")) //regular write
//the STARTTLS command has been received, switch to tls.Conn and handshake
client.Conn = tls.Server(client.Conn, &TlsConfig) //client.Conn should be now of type tls.Conn
//either casting or not give me the same results
client.Conn.Handshake() //not necessary, it is called on the first Read() or Write() by default
//...
client.Conn.Write([]byte("Hello again!")) //writes clear, unencrypted text
//...
rdr := bufio.NewReader(client.Conn) //might this be the culprit? I don't think it is, since it should just wrap the regular functions
line, err := rdr.ReadString/*or Line*/('\n')
//...
//line = something like À"À!27ÀÀ9ÀÀÀÀ and other client-encrypted text
I've seen that numerous people, including the standard `net/smtp` package, use the `text/proto` package to parse client commands. However, I want to use my own (and also want to sort this out). As in the comment earlier, I don't think the culprit lies here, since it should just wrap functions, shouldn't it?
Might it be the `client.Conn = tls.Server(client.Conn, &TlsConfig)` object switch?
The SSL key and certificate I'm using are selfsigned, generated with OpenSSL.
To test, I'm using the two methods suggested in the StackOverflow question linked above: `openssl s_client -starttls smtp -crlf [-tls1] -connect localhost:25` and a simple `net/smtp.SendMail()` call. I'm compiling against Go 1.2.1 (linux/amd64).
I've also tried sniffing with Wireshark, and indeed it led me to know what I said above. Also, calling Handshake() doesn't apparently actually handshake.
What am I doing wrong?
</details>
# 答案1
**得分**: 0
尝试将你的TLS连接存储在一个新的类型为`*tls.Conn`的变量中。发起握手并检查`ConnectionState()`返回的内容。
<details>
<summary>英文:</summary>
Try storing your TLS connection in a new variable of type `*tls.Conn`. Initiate a handshake and check what `ConnectionState()` tells.
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论