15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2010 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/cert/pem_tokenizer.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/base64.h" 85e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/string_util.h" 95e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/stringprintf.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kPEMSearchBlock[] = "-----BEGIN "; 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kPEMBeginBlock[] = "-----BEGIN %s-----"; 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kPEMEndBlock[] = "-----END %s-----"; 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net { 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::StringPiece; 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct PEMTokenizer::PEMType { 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string type; 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string header; 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string footer; 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PEMTokenizer::PEMTokenizer( 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const StringPiece& str, 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::vector<std::string>& allowed_block_types) { 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Init(str, allowed_block_types); 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PEMTokenizer::~PEMTokenizer() { 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PEMTokenizer::GetNext() { 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (pos_ != StringPiece::npos) { 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Scan for the beginning of the next PEM encoded block. 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pos_ = str_.find(kPEMSearchBlock, pos_); 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pos_ == StringPiece::npos) 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; // No more PEM blocks 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<PEMType>::const_iterator it; 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check to see if it is of an acceptable block type. 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (it = block_types_.begin(); it != block_types_.end(); ++it) { 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!str_.substr(pos_).starts_with(it->header)) 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Look for a footer matching the header. If none is found, then all 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // data following this point is invalid and should not be parsed. 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StringPiece::size_type footer_pos = str_.find(it->footer, pos_); 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (footer_pos == StringPiece::npos) { 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pos_ = StringPiece::npos; 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Chop off the header and footer and parse the data in between. 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StringPiece::size_type data_begin = pos_ + it->header.size(); 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pos_ = footer_pos + it->footer.size(); 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) block_type_ = it->type; 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StringPiece encoded = str_.substr(data_begin, 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) footer_pos - data_begin); 66a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!base::Base64Decode(base::CollapseWhitespaceASCII(encoded.as_string(), 67a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) true), &data_)) { 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The most likely cause for a decode failure is a datatype that 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // includes PEM headers, which are not supported. 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the block did not match any acceptable type, move past it and 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // continue the search. Otherwise, |pos_| has been updated to the most 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // appropriate search position to continue searching from and should not 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // be adjusted. 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (it == block_types_.end()) 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pos_ += sizeof(kPEMSearchBlock); 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PEMTokenizer::Init( 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const StringPiece& str, 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::vector<std::string>& allowed_block_types) { 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) str_ = str; 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pos_ = 0; 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Construct PEM header/footer strings for all the accepted types, to 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // reduce parsing later. 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (std::vector<std::string>::const_iterator it = 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) allowed_block_types.begin(); it != allowed_block_types.end(); ++it) { 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PEMType allowed_type; 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) allowed_type.type = *it; 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) allowed_type.header = base::StringPrintf(kPEMBeginBlock, it->c_str()); 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) allowed_type.footer = base::StringPrintf(kPEMEndBlock, it->c_str()); 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) block_types_.push_back(allowed_type); 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace net 106