roughtime.googlesource.com/roughtime.git@v0.0.0-20201210012726-dd529367052d/go/protocol/protocol.go (about) 1 // Copyright 2016 The Roughtime 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 15 // Package protocol implements the core of the Roughtime protocol. 16 package protocol 17 18 import ( 19 "bytes" 20 "crypto/sha512" 21 "encoding/binary" 22 "errors" 23 "io" 24 "math" 25 "sort" 26 27 "golang.org/x/crypto/ed25519" 28 ) 29 30 const ( 31 // NonceSize is the number of bytes in a nonce. 32 NonceSize = sha512.Size 33 // MinRequestSize is the minimum number of bytes in a request. 34 MinRequestSize = 1024 35 36 certificateContext = "RoughTime v1 delegation signature--\x00" 37 signedResponseContext = "RoughTime v1 response signature\x00" 38 ) 39 40 // makeTag converts a four character string into a Roughtime tag value. 41 func makeTag(tag string) uint32 { 42 if len(tag) != 4 { 43 panic("makeTag: len(tag) != 4: " + tag) 44 } 45 46 return uint32(tag[0]) | uint32(tag[1])<<8 | uint32(tag[2])<<16 | uint32(tag[3])<<24 47 } 48 49 var ( 50 // Various tags used in the Roughtime protocol. 51 tagCERT = makeTag("CERT") 52 tagDELE = makeTag("DELE") 53 tagINDX = makeTag("INDX") 54 tagMAXT = makeTag("MAXT") 55 tagMIDP = makeTag("MIDP") 56 tagMINT = makeTag("MINT") 57 tagNONC = makeTag("NONC") 58 tagPAD = makeTag("PAD\xff") 59 tagPATH = makeTag("PATH") 60 tagPUBK = makeTag("PUBK") 61 tagRADI = makeTag("RADI") 62 tagROOT = makeTag("ROOT") 63 tagSIG = makeTag("SIG\x00") 64 tagSREP = makeTag("SREP") 65 66 // TagNonce names the bytestring containing the client's nonce. 67 TagNonce = tagNONC 68 ) 69 70 // tagsSlice is the type of an array of tags. It provides utility functions so 71 // that they can be sorted. 72 type tagsSlice []uint32 73 74 func (t tagsSlice) Len() int { return len(t) } 75 func (t tagsSlice) Less(i, j int) bool { return t[i] < t[j] } 76 func (t tagsSlice) Swap(i, j int) { t[i], t[j] = t[j], t[i] } 77 78 // Encode converts a map of tags to bytestrings into an encoded message. The 79 // number of elements in msg and the sum of the lengths of all the bytestrings 80 // must be ≤ 2**32. 81 func Encode(msg map[uint32][]byte) ([]byte, error) { 82 if len(msg) == 0 { 83 return make([]byte, 4), nil 84 } 85 86 if len(msg) >= math.MaxInt32 { 87 return nil, errors.New("encode: too many tags") 88 } 89 90 var payloadSum uint64 91 for _, payload := range msg { 92 if len(payload)%4 != 0 { 93 return nil, errors.New("encode: length of value is not a multiple of four") 94 } 95 payloadSum += uint64(len(payload)) 96 } 97 if payloadSum >= 1<<32 { 98 return nil, errors.New("encode: payloads too large") 99 } 100 101 tags := tagsSlice(make([]uint32, 0, len(msg))) 102 for tag := range msg { 103 tags = append(tags, tag) 104 } 105 sort.Sort(tags) 106 107 numTags := uint64(len(tags)) 108 109 encoded := make([]byte, 4*(1+numTags-1+numTags)+payloadSum) 110 binary.LittleEndian.PutUint32(encoded, uint32(len(tags))) 111 offsets := encoded[4:] 112 tagBytes := encoded[4*(1+(numTags-1)):] 113 payloads := encoded[4*(1+(numTags-1)+numTags):] 114 115 currentOffset := uint32(0) 116 117 for i, tag := range tags { 118 payload := msg[tag] 119 if i > 0 { 120 binary.LittleEndian.PutUint32(offsets, currentOffset) 121 offsets = offsets[4:] 122 } 123 124 binary.LittleEndian.PutUint32(tagBytes, tag) 125 tagBytes = tagBytes[4:] 126 127 if len(payload) > 0 { 128 copy(payloads, payload) 129 payloads = payloads[len(payload):] 130 currentOffset += uint32(len(payload)) 131 } 132 } 133 134 return encoded, nil 135 } 136 137 // Decode parses the output of encode back into a map of tags to bytestrings. 138 func Decode(bytes []byte) (map[uint32][]byte, error) { 139 if len(bytes) < 4 { 140 return nil, errors.New("decode: message too short to be valid") 141 } 142 if len(bytes)%4 != 0 { 143 return nil, errors.New("decode: message is not a multiple of four bytes") 144 } 145 146 numTags := uint64(binary.LittleEndian.Uint32(bytes)) 147 148 if numTags == 0 { 149 return make(map[uint32][]byte), nil 150 } 151 152 minLen := 4 * (1 + (numTags - 1) + numTags) 153 154 if uint64(len(bytes)) < minLen { 155 return nil, errors.New("decode: message too short to be valid") 156 } 157 158 offsets := bytes[4:] 159 tags := bytes[4*(1+numTags-1):] 160 payloads := bytes[minLen:] 161 162 if len(payloads) > math.MaxInt32 { 163 return nil, errors.New("decode: message too large") 164 } 165 payloadLength := uint32(len(payloads)) 166 167 currentOffset := uint32(0) 168 var lastTag uint32 169 ret := make(map[uint32][]byte) 170 171 for i := uint64(0); i < numTags; i++ { 172 tag := binary.LittleEndian.Uint32(tags) 173 tags = tags[4:] 174 175 if i > 0 && lastTag >= tag { 176 return nil, errors.New("decode: tags out of order") 177 } 178 179 var nextOffset uint32 180 if i < numTags-1 { 181 nextOffset = binary.LittleEndian.Uint32(offsets) 182 offsets = offsets[4:] 183 } else { 184 nextOffset = payloadLength 185 } 186 187 if nextOffset%4 != 0 { 188 return nil, errors.New("decode: payload length is not a multiple of four bytes") 189 } 190 191 if nextOffset < currentOffset { 192 return nil, errors.New("decode: offsets out of order") 193 } 194 195 length := nextOffset - currentOffset 196 if uint32(len(payloads)) < length { 197 return nil, errors.New("decode: message truncated") 198 } 199 200 payload := payloads[:length] 201 payloads = payloads[length:] 202 ret[tag] = payload 203 currentOffset = nextOffset 204 lastTag = tag 205 } 206 207 return ret, nil 208 } 209 210 // messageOverhead returns the number of bytes needed for Encode to encode the 211 // given number of tags. 212 func messageOverhead(numTags int) int { 213 return 4 * 2 * numTags 214 } 215 216 // CalculateChainNonce calculates the nonce to be used in the next request in a 217 // chain given a reply and a blinding factor. 218 func CalculateChainNonce(prevReply, blind []byte) (nonce [NonceSize]byte) { 219 h := sha512.New() 220 h.Write(prevReply) 221 prevReplyHash := h.Sum(nil) 222 223 h.Reset() 224 h.Write(prevReplyHash) 225 h.Write(blind) 226 h.Sum(nonce[:0]) 227 228 return nonce 229 } 230 231 // CreateRequest creates a Roughtime request given an entropy source and the 232 // contents of a previous reply for chaining. If this request is the first of a 233 // chain, prevReply can be empty. It returns the nonce (needed to verify the 234 // reply), the blind (needed to prove correct chaining to an external party) 235 // and the request itself. 236 func CreateRequest(rand io.Reader, prevReply []byte) (nonce, blind [NonceSize]byte, request []byte, err error) { 237 if _, err := io.ReadFull(rand, blind[:]); err != nil { 238 return nonce, blind, nil, err 239 } 240 241 nonce = CalculateChainNonce(prevReply, blind[:]) 242 243 padding := make([]byte, MinRequestSize-messageOverhead(2)-len(nonce)) 244 msg, err := Encode(map[uint32][]byte{ 245 tagNONC: nonce[:], 246 tagPAD: padding, 247 }) 248 if err != nil { 249 return nonce, blind, nil, err 250 } 251 252 return nonce, blind, msg, nil 253 } 254 255 // tree represents a Merkle tree of nonces. Each element of values is a layer 256 // in the tree, with the widest layer first. 257 type tree struct { 258 values [][][NonceSize]byte 259 } 260 261 var ( 262 hashLeafTweak = []byte{0} 263 hashNodeTweak = []byte{1} 264 ) 265 266 // hashLeaf hashes an nonce to form the leaf of the Merkle tree. 267 func hashLeaf(out *[sha512.Size]byte, in []byte) { 268 h := sha512.New() 269 h.Write(hashLeafTweak) 270 h.Write(in) 271 h.Sum(out[:0]) 272 } 273 274 // hashNode hashes two child elements of the Merkle tree to produce an interior 275 // node. 276 func hashNode(out *[sha512.Size]byte, left, right []byte) { 277 h := sha512.New() 278 h.Write(hashNodeTweak) 279 h.Write(left) 280 h.Write(right) 281 h.Sum(out[:0]) 282 } 283 284 // newTree creates a Merkle tree given one or more nonces. 285 func newTree(nonces [][]byte) *tree { 286 if len(nonces) == 0 { 287 panic("newTree: passed empty slice") 288 } 289 290 levels := 1 291 width := len(nonces) 292 for width > 1 { 293 width = (width + 1) / 2 294 levels++ 295 } 296 297 ret := &tree{ 298 values: make([][][NonceSize]byte, 0, levels), 299 } 300 301 leaves := make([][NonceSize]byte, ((len(nonces)+1)/2)*2) 302 for i, nonce := range nonces { 303 var leaf [NonceSize]byte 304 hashLeaf(&leaf, nonce) 305 leaves[i] = leaf 306 } 307 // Fill any extra leaves with an existing leaf, to simplify analysis 308 // that we are not inadvertently signing other messages. 309 for i := len(nonces); i < len(leaves); i++ { 310 leaves[i] = leaves[0] 311 } 312 ret.values = append(ret.values, leaves) 313 314 for i := 1; i < levels; i++ { 315 lastLevel := ret.values[i-1] 316 width := len(lastLevel) / 2 317 if width%2 == 1 { 318 width++ 319 } 320 level := make([][NonceSize]byte, width) 321 for j := 0; j < len(lastLevel)/2; j++ { 322 hashNode(&level[j], lastLevel[j*2][:], lastLevel[j*2+1][:]) 323 } 324 // Fill the extra node with an existing node, to simplify 325 // analysis that we are not inadvertently signing other 326 // messages. 327 if len(lastLevel)/2 < len(level) { 328 level[len(lastLevel)/2] = level[0] 329 } 330 ret.values = append(ret.values, level) 331 } 332 333 return ret 334 } 335 336 // Root returns the root value of t. 337 func (t *tree) Root() *[NonceSize]byte { 338 return &t.values[len(t.values)-1][0] 339 } 340 341 // Levels returns the number of levels in t. 342 func (t *tree) Levels() int { 343 return len(t.values) 344 } 345 346 // Path returns elements from t needed to prove, given the root, that the leaf 347 // at the given index is in the tree. 348 func (t *tree) Path(index int) (path [][]byte) { 349 path = make([][]byte, 0, len(t.values)) 350 351 for level := 0; level < len(t.values)-1; level++ { 352 if index%2 == 1 { 353 path = append(path, t.values[level][index-1][:]) 354 } else { 355 path = append(path, t.values[level][index+1][:]) 356 } 357 358 index /= 2 359 } 360 361 return path 362 } 363 364 // CreateReplies signs, using privateKey, a batch of nonces along with the 365 // given time and radius in microseconds. It returns one reply for each nonce 366 // using that signature and includes cert in each. 367 func CreateReplies(nonces [][]byte, midpoint uint64, radius uint32, cert []byte, privateKey []byte) ([][]byte, error) { 368 if len(nonces) == 0 { 369 return nil, nil 370 } 371 372 tree := newTree(nonces) 373 374 var midpointBytes [8]byte 375 binary.LittleEndian.PutUint64(midpointBytes[:], midpoint) 376 var radiusBytes [4]byte 377 binary.LittleEndian.PutUint32(radiusBytes[:], radius) 378 379 signedReply := map[uint32][]byte{ 380 tagMIDP: midpointBytes[:], 381 tagRADI: radiusBytes[:], 382 tagROOT: tree.Root()[:], 383 } 384 signedReplyBytes, err := Encode(signedReply) 385 if err != nil { 386 return nil, err 387 } 388 389 toBeSigned := signedResponseContext + string(signedReplyBytes) 390 sig := ed25519.Sign(privateKey, []byte(toBeSigned)) 391 392 reply := map[uint32][]byte{ 393 tagSREP: signedReplyBytes, 394 tagSIG: sig, 395 tagCERT: cert, 396 } 397 398 replies := make([][]byte, 0, len(nonces)) 399 400 for i := range nonces { 401 var indexBytes [4]byte 402 binary.LittleEndian.PutUint32(indexBytes[:], uint32(i)) 403 reply[tagINDX] = indexBytes[:] 404 405 path := tree.Path(i) 406 pathBytes := make([]byte, 0, NonceSize*len(path)) 407 for _, pathStep := range path { 408 pathBytes = append(pathBytes, pathStep...) 409 } 410 reply[tagPATH] = pathBytes 411 412 replyBytes, err := Encode(reply) 413 if err != nil { 414 return nil, err 415 } 416 417 replies = append(replies, replyBytes) 418 } 419 420 return replies, nil 421 } 422 423 // CreateCertificate returns a signed certificate, using rootPrivateKey, 424 // delegating authority for the given timestamp to publicKey. 425 func CreateCertificate(minTime, maxTime uint64, publicKey, rootPrivateKey []byte) (certBytes []byte, err error) { 426 if maxTime < minTime { 427 return nil, errors.New("protocol: maxTime < minTime") 428 } 429 430 var minTimeBytes, maxTimeBytes [8]byte 431 binary.LittleEndian.PutUint64(minTimeBytes[:], minTime) 432 binary.LittleEndian.PutUint64(maxTimeBytes[:], maxTime) 433 434 signed := map[uint32][]byte{ 435 tagPUBK: publicKey, 436 tagMINT: minTimeBytes[:], 437 tagMAXT: maxTimeBytes[:], 438 } 439 440 signedBytes, err := Encode(signed) 441 if err != nil { 442 return nil, err 443 } 444 445 toBeSigned := certificateContext + string(signedBytes) 446 sig := ed25519.Sign(rootPrivateKey, []byte(toBeSigned)) 447 448 cert := map[uint32][]byte{ 449 tagSIG: sig, 450 tagDELE: signedBytes, 451 } 452 453 return Encode(cert) 454 } 455 456 func getValue(msg map[uint32][]byte, tag uint32, name string) (value []byte, err error) { 457 value, ok := msg[tag] 458 if !ok { 459 return nil, errors.New("protocol: missing " + name) 460 } 461 return value, nil 462 } 463 464 func getFixedLength(msg map[uint32][]byte, tag uint32, name string, length int) (value []byte, err error) { 465 value, err = getValue(msg, tag, name) 466 if err != nil { 467 return nil, err 468 } 469 if len(value) != length { 470 return nil, errors.New("protocol: incorrect length for " + name) 471 } 472 return value, nil 473 } 474 475 func getUint32(msg map[uint32][]byte, tag uint32, name string) (result uint32, err error) { 476 valueBytes, err := getFixedLength(msg, tag, name, 4) 477 if err != nil { 478 return 0, err 479 } 480 return binary.LittleEndian.Uint32(valueBytes), nil 481 } 482 483 func getUint64(msg map[uint32][]byte, tag uint32, name string) (result uint64, err error) { 484 valueBytes, err := getFixedLength(msg, tag, name, 8) 485 if err != nil { 486 return 0, err 487 } 488 return binary.LittleEndian.Uint64(valueBytes), nil 489 } 490 491 func getSubmessage(msg map[uint32][]byte, tag uint32, name string) (result map[uint32][]byte, err error) { 492 valueBytes, err := getValue(msg, tag, name) 493 if err != nil { 494 return nil, err 495 } 496 497 result, err = Decode(valueBytes) 498 if err != nil { 499 return nil, errors.New("protocol: failed to parse " + name + ": " + err.Error()) 500 } 501 502 return result, nil 503 } 504 505 // VerifyReply parses the Roughtime reply in replyBytes, authenticates it using 506 // publicKey and verifies that nonce is included in it. It returns the included 507 // timestamp and radius. 508 func VerifyReply(replyBytes, publicKey []byte, nonce [NonceSize]byte) (time uint64, radius uint32, err error) { 509 reply, err := Decode(replyBytes) 510 if err != nil { 511 return 0, 0, errors.New("protocol: failed to parse top-level reply: " + err.Error()) 512 } 513 514 cert, err := getSubmessage(reply, tagCERT, "certificate") 515 if err != nil { 516 return 0, 0, err 517 } 518 519 signatureBytes, err := getFixedLength(cert, tagSIG, "signature", ed25519.SignatureSize) 520 if err != nil { 521 return 0, 0, err 522 } 523 524 delegationBytes, err := getValue(cert, tagDELE, "delegation") 525 if err != nil { 526 return 0, 0, err 527 } 528 529 if !ed25519.Verify(publicKey, []byte(certificateContext+string(delegationBytes)), signatureBytes) { 530 return 0, 0, errors.New("protocol: invalid delegation signature") 531 } 532 533 delegation, err := Decode(delegationBytes) 534 if err != nil { 535 return 0, 0, errors.New("protocol: failed to parse delegation: " + err.Error()) 536 } 537 538 minTime, err := getUint64(delegation, tagMINT, "minimum time") 539 if err != nil { 540 return 0, 0, err 541 } 542 543 maxTime, err := getUint64(delegation, tagMAXT, "maximum time") 544 if err != nil { 545 return 0, 0, err 546 } 547 548 delegatedPublicKey, err := getFixedLength(delegation, tagPUBK, "public key", ed25519.PublicKeySize) 549 if err != nil { 550 return 0, 0, err 551 } 552 553 responseSigBytes, err := getFixedLength(reply, tagSIG, "signature", ed25519.SignatureSize) 554 if err != nil { 555 return 0, 0, err 556 } 557 558 signedResponseBytes, ok := reply[tagSREP] 559 if !ok { 560 return 0, 0, errors.New("protocol: response is missing signed portion") 561 } 562 563 if !ed25519.Verify(delegatedPublicKey, []byte(signedResponseContext+string(signedResponseBytes)), responseSigBytes) { 564 return 0, 0, errors.New("protocol: invalid response signature") 565 } 566 567 signedResponse, err := Decode(signedResponseBytes) 568 if err != nil { 569 return 0, 0, errors.New("protocol: failed to parse signed response: " + err.Error()) 570 } 571 572 root, err := getFixedLength(signedResponse, tagROOT, "root", sha512.Size) 573 if err != nil { 574 return 0, 0, err 575 } 576 577 midpoint, err := getUint64(signedResponse, tagMIDP, "midpoint") 578 if err != nil { 579 return 0, 0, err 580 } 581 582 radius, err = getUint32(signedResponse, tagRADI, "radius") 583 if err != nil { 584 return 0, 0, err 585 } 586 587 if maxTime < minTime { 588 return 0, 0, errors.New("protocol: invalid delegation range") 589 } 590 591 if midpoint < minTime || maxTime < midpoint { 592 return 0, 0, errors.New("protocol: timestamp out of range for delegation") 593 } 594 595 index, err := getUint32(reply, tagINDX, "index") 596 if err != nil { 597 return 0, 0, err 598 } 599 600 path, err := getValue(reply, tagPATH, "path") 601 if err != nil { 602 return 0, 0, err 603 } 604 if len(path)%sha512.Size != 0 { 605 return 0, 0, errors.New("protocol: path is not a multiple of the hash size") 606 } 607 608 var hash [sha512.Size]byte 609 hashLeaf(&hash, nonce[:]) 610 611 for len(path) > 0 { 612 pathElementIsRight := index&1 == 0 613 if pathElementIsRight { 614 hashNode(&hash, hash[:], path[:sha512.Size]) 615 } else { 616 hashNode(&hash, path[:sha512.Size], hash[:]) 617 } 618 619 index >>= 1 620 path = path[sha512.Size:] 621 } 622 623 if !bytes.Equal(hash[:], root) { 624 return 0, 0, errors.New("protocol: calculated tree root doesn't match signed root") 625 } 626 627 return midpoint, radius, nil 628 }