bio.go 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. // Copyright (C) 2017. See AUTHORS.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package openssl
  15. // #include "shim.h"
  16. import "C"
  17. import (
  18. "errors"
  19. "io"
  20. "reflect"
  21. "sync"
  22. "unsafe"
  23. )
  24. const (
  25. SSLRecordSize = 16 * 1024
  26. )
  27. func nonCopyGoBytes(ptr uintptr, length int) []byte {
  28. var slice []byte
  29. header := (*reflect.SliceHeader)(unsafe.Pointer(&slice))
  30. header.Cap = length
  31. header.Len = length
  32. header.Data = ptr
  33. return slice
  34. }
  35. func nonCopyCString(data *C.char, size C.int) []byte {
  36. return nonCopyGoBytes(uintptr(unsafe.Pointer(data)), int(size))
  37. }
  38. var writeBioMapping = newMapping()
  39. type writeBio struct {
  40. data_mtx sync.Mutex
  41. op_mtx sync.Mutex
  42. buf []byte
  43. release_buffers bool
  44. }
  45. func loadWritePtr(b *C.BIO) *writeBio {
  46. t := token(C.X_BIO_get_data(b))
  47. return (*writeBio)(writeBioMapping.Get(t))
  48. }
  49. func bioClearRetryFlags(b *C.BIO) {
  50. C.X_BIO_clear_flags(b, C.BIO_FLAGS_RWS|C.BIO_FLAGS_SHOULD_RETRY)
  51. }
  52. func bioSetRetryRead(b *C.BIO) {
  53. C.X_BIO_set_flags(b, C.BIO_FLAGS_READ|C.BIO_FLAGS_SHOULD_RETRY)
  54. }
  55. //export go_write_bio_write
  56. func go_write_bio_write(b *C.BIO, data *C.char, size C.int) (rc C.int) {
  57. defer func() {
  58. if err := recover(); err != nil {
  59. logger.Critf("openssl: writeBioWrite panic'd: %v", err)
  60. rc = -1
  61. }
  62. }()
  63. ptr := loadWritePtr(b)
  64. if ptr == nil || data == nil || size < 0 {
  65. return -1
  66. }
  67. ptr.data_mtx.Lock()
  68. defer ptr.data_mtx.Unlock()
  69. bioClearRetryFlags(b)
  70. ptr.buf = append(ptr.buf, nonCopyCString(data, size)...)
  71. return size
  72. }
  73. //export go_write_bio_ctrl
  74. func go_write_bio_ctrl(b *C.BIO, cmd C.int, arg1 C.long, arg2 unsafe.Pointer) (
  75. rc C.long) {
  76. defer func() {
  77. if err := recover(); err != nil {
  78. logger.Critf("openssl: writeBioCtrl panic'd: %v", err)
  79. rc = -1
  80. }
  81. }()
  82. switch cmd {
  83. case C.BIO_CTRL_WPENDING:
  84. return writeBioPending(b)
  85. case C.BIO_CTRL_DUP, C.BIO_CTRL_FLUSH:
  86. return 1
  87. default:
  88. return 0
  89. }
  90. }
  91. func writeBioPending(b *C.BIO) C.long {
  92. ptr := loadWritePtr(b)
  93. if ptr == nil {
  94. return 0
  95. }
  96. ptr.data_mtx.Lock()
  97. defer ptr.data_mtx.Unlock()
  98. return C.long(len(ptr.buf))
  99. }
  100. func (b *writeBio) WriteTo(w io.Writer) (rv int64, err error) {
  101. b.op_mtx.Lock()
  102. defer b.op_mtx.Unlock()
  103. // write whatever data we currently have
  104. b.data_mtx.Lock()
  105. data := b.buf
  106. b.data_mtx.Unlock()
  107. if len(data) == 0 {
  108. return 0, nil
  109. }
  110. n, err := w.Write(data)
  111. // subtract however much data we wrote from the buffer
  112. b.data_mtx.Lock()
  113. b.buf = b.buf[:copy(b.buf, b.buf[n:])]
  114. if b.release_buffers && len(b.buf) == 0 {
  115. b.buf = nil
  116. }
  117. b.data_mtx.Unlock()
  118. return int64(n), err
  119. }
  120. func (self *writeBio) Disconnect(b *C.BIO) {
  121. if loadWritePtr(b) == self {
  122. writeBioMapping.Del(token(C.X_BIO_get_data(b)))
  123. C.X_BIO_set_data(b, nil)
  124. }
  125. }
  126. func (b *writeBio) MakeCBIO() *C.BIO {
  127. rv := C.X_BIO_new_write_bio()
  128. token := writeBioMapping.Add(unsafe.Pointer(b))
  129. C.X_BIO_set_data(rv, unsafe.Pointer(token))
  130. return rv
  131. }
  132. var readBioMapping = newMapping()
  133. type readBio struct {
  134. data_mtx sync.Mutex
  135. op_mtx sync.Mutex
  136. buf []byte
  137. eof bool
  138. release_buffers bool
  139. }
  140. func loadReadPtr(b *C.BIO) *readBio {
  141. return (*readBio)(readBioMapping.Get(token(C.X_BIO_get_data(b))))
  142. }
  143. //export go_read_bio_read
  144. func go_read_bio_read(b *C.BIO, data *C.char, size C.int) (rc C.int) {
  145. defer func() {
  146. if err := recover(); err != nil {
  147. logger.Critf("openssl: go_read_bio_read panic'd: %v", err)
  148. rc = -1
  149. }
  150. }()
  151. ptr := loadReadPtr(b)
  152. if ptr == nil || size < 0 {
  153. return -1
  154. }
  155. ptr.data_mtx.Lock()
  156. defer ptr.data_mtx.Unlock()
  157. bioClearRetryFlags(b)
  158. if len(ptr.buf) == 0 {
  159. if ptr.eof {
  160. return 0
  161. }
  162. bioSetRetryRead(b)
  163. return -1
  164. }
  165. if size == 0 || data == nil {
  166. return C.int(len(ptr.buf))
  167. }
  168. n := copy(nonCopyCString(data, size), ptr.buf)
  169. ptr.buf = ptr.buf[:copy(ptr.buf, ptr.buf[n:])]
  170. if ptr.release_buffers && len(ptr.buf) == 0 {
  171. ptr.buf = nil
  172. }
  173. return C.int(n)
  174. }
  175. //export go_read_bio_ctrl
  176. func go_read_bio_ctrl(b *C.BIO, cmd C.int, arg1 C.long, arg2 unsafe.Pointer) (
  177. rc C.long) {
  178. defer func() {
  179. if err := recover(); err != nil {
  180. logger.Critf("openssl: readBioCtrl panic'd: %v", err)
  181. rc = -1
  182. }
  183. }()
  184. switch cmd {
  185. case C.BIO_CTRL_PENDING:
  186. return readBioPending(b)
  187. case C.BIO_CTRL_DUP, C.BIO_CTRL_FLUSH:
  188. return 1
  189. default:
  190. return 0
  191. }
  192. }
  193. func readBioPending(b *C.BIO) C.long {
  194. ptr := loadReadPtr(b)
  195. if ptr == nil {
  196. return 0
  197. }
  198. ptr.data_mtx.Lock()
  199. defer ptr.data_mtx.Unlock()
  200. return C.long(len(ptr.buf))
  201. }
  202. func (b *readBio) ReadFromOnce(r io.Reader) (n int, err error) {
  203. b.op_mtx.Lock()
  204. defer b.op_mtx.Unlock()
  205. // make sure we have a destination that fits at least one SSL record
  206. b.data_mtx.Lock()
  207. if cap(b.buf) < len(b.buf)+SSLRecordSize {
  208. new_buf := make([]byte, len(b.buf), len(b.buf)+SSLRecordSize)
  209. copy(new_buf, b.buf)
  210. b.buf = new_buf
  211. }
  212. dst := b.buf[len(b.buf):cap(b.buf)]
  213. dst_slice := b.buf
  214. b.data_mtx.Unlock()
  215. n, err = r.Read(dst)
  216. b.data_mtx.Lock()
  217. defer b.data_mtx.Unlock()
  218. if n > 0 {
  219. if len(dst_slice) != len(b.buf) {
  220. // someone shrunk the buffer, so we read in too far ahead and we
  221. // need to slide backwards
  222. copy(b.buf[len(b.buf):len(b.buf)+n], dst)
  223. }
  224. b.buf = b.buf[:len(b.buf)+n]
  225. }
  226. return n, err
  227. }
  228. func (b *readBio) MakeCBIO() *C.BIO {
  229. rv := C.X_BIO_new_read_bio()
  230. token := readBioMapping.Add(unsafe.Pointer(b))
  231. C.X_BIO_set_data(rv, unsafe.Pointer(token))
  232. return rv
  233. }
  234. func (self *readBio) Disconnect(b *C.BIO) {
  235. if loadReadPtr(b) == self {
  236. readBioMapping.Del(token(C.X_BIO_get_data(b)))
  237. C.X_BIO_set_data(b, nil)
  238. }
  239. }
  240. func (b *readBio) MarkEOF() {
  241. b.data_mtx.Lock()
  242. defer b.data_mtx.Unlock()
  243. b.eof = true
  244. }
  245. type anyBio C.BIO
  246. func asAnyBio(b *C.BIO) *anyBio { return (*anyBio)(b) }
  247. func (b *anyBio) Read(buf []byte) (n int, err error) {
  248. if len(buf) == 0 {
  249. return 0, nil
  250. }
  251. n = int(C.X_BIO_read((*C.BIO)(b), unsafe.Pointer(&buf[0]), C.int(len(buf))))
  252. if n <= 0 {
  253. return 0, io.EOF
  254. }
  255. return n, nil
  256. }
  257. func (b *anyBio) Write(buf []byte) (written int, err error) {
  258. if len(buf) == 0 {
  259. return 0, nil
  260. }
  261. n := int(C.X_BIO_write((*C.BIO)(b), unsafe.Pointer(&buf[0]),
  262. C.int(len(buf))))
  263. if n != len(buf) {
  264. return n, errors.New("BIO write failed")
  265. }
  266. return n, nil
  267. }