summaryrefslogtreecommitdiff
path: root/vendor/github.com/pion/dtls/v2/pkg/protocol/handshake/handshake.go
blob: 4aa493e753efc8e0570bde12696ff019f5bd0d3d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// Package handshake provides the DTLS wire protocol for handshakes
package handshake

import (
	"github.com/pion/dtls/v2/internal/util"
	"github.com/pion/dtls/v2/pkg/protocol"
)

// Type is the unique identifier for each handshake message
// https://tools.ietf.org/html/rfc5246#section-7.4
type Type uint8

// Types of DTLS Handshake messages we know about
const (
	TypeHelloRequest       Type = 0
	TypeClientHello        Type = 1
	TypeServerHello        Type = 2
	TypeHelloVerifyRequest Type = 3
	TypeCertificate        Type = 11
	TypeServerKeyExchange  Type = 12
	TypeCertificateRequest Type = 13
	TypeServerHelloDone    Type = 14
	TypeCertificateVerify  Type = 15
	TypeClientKeyExchange  Type = 16
	TypeFinished           Type = 20
)

// String returns the string representation of this type
func (t Type) String() string {
	switch t {
	case TypeHelloRequest:
		return "HelloRequest"
	case TypeClientHello:
		return "ClientHello"
	case TypeServerHello:
		return "ServerHello"
	case TypeHelloVerifyRequest:
		return "HelloVerifyRequest"
	case TypeCertificate:
		return "TypeCertificate"
	case TypeServerKeyExchange:
		return "ServerKeyExchange"
	case TypeCertificateRequest:
		return "CertificateRequest"
	case TypeServerHelloDone:
		return "ServerHelloDone"
	case TypeCertificateVerify:
		return "CertificateVerify"
	case TypeClientKeyExchange:
		return "ClientKeyExchange"
	case TypeFinished:
		return "Finished"
	}
	return ""
}

// Message is the body of a Handshake datagram
type Message interface {
	Marshal() ([]byte, error)
	Unmarshal(data []byte) error

	Type() Type
}

// Handshake protocol is responsible for selecting a cipher spec and
// generating a master secret, which together comprise the primary
// cryptographic parameters associated with a secure session.  The
// handshake protocol can also optionally authenticate parties who have
// certificates signed by a trusted certificate authority.
// https://tools.ietf.org/html/rfc5246#section-7.3
type Handshake struct {
	Header  Header
	Message Message
}

// ContentType returns what kind of content this message is carying
func (h Handshake) ContentType() protocol.ContentType {
	return protocol.ContentTypeHandshake
}

// Marshal encodes a handshake into a binary message
func (h *Handshake) Marshal() ([]byte, error) {
	if h.Message == nil {
		return nil, errHandshakeMessageUnset
	} else if h.Header.FragmentOffset != 0 {
		return nil, errUnableToMarshalFragmented
	}

	msg, err := h.Message.Marshal()
	if err != nil {
		return nil, err
	}

	h.Header.Length = uint32(len(msg))
	h.Header.FragmentLength = h.Header.Length
	h.Header.Type = h.Message.Type()
	header, err := h.Header.Marshal()
	if err != nil {
		return nil, err
	}

	return append(header, msg...), nil
}

// Unmarshal decodes a handshake from a binary message
func (h *Handshake) Unmarshal(data []byte) error {
	if err := h.Header.Unmarshal(data); err != nil {
		return err
	}

	reportedLen := util.BigEndianUint24(data[1:])
	if uint32(len(data)-HeaderLength) != reportedLen {
		return errLengthMismatch
	} else if reportedLen != h.Header.FragmentLength {
		return errLengthMismatch
	}

	switch Type(data[0]) {
	case TypeHelloRequest:
		return errNotImplemented
	case TypeClientHello:
		h.Message = &MessageClientHello{}
	case TypeHelloVerifyRequest:
		h.Message = &MessageHelloVerifyRequest{}
	case TypeServerHello:
		h.Message = &MessageServerHello{}
	case TypeCertificate:
		h.Message = &MessageCertificate{}
	case TypeServerKeyExchange:
		h.Message = &MessageServerKeyExchange{}
	case TypeCertificateRequest:
		h.Message = &MessageCertificateRequest{}
	case TypeServerHelloDone:
		h.Message = &MessageServerHelloDone{}
	case TypeClientKeyExchange:
		h.Message = &MessageClientKeyExchange{}
	case TypeFinished:
		h.Message = &MessageFinished{}
	case TypeCertificateVerify:
		h.Message = &MessageCertificateVerify{}
	default:
		return errNotImplemented
	}
	return h.Message.Unmarshal(data[HeaderLength:])
}